Midterm 2, Fall 2022: Capturing Data Changes for Slowly Changing Dimensions

Version 1.0.0

Version History

1.0.0

  • Initial release.

All of the header information is important. Please read it..

Topics, number of exercises: This problem builds on your knowledge of working with tabular data. It has 9 exercises, numbered 0 to 8. There are 19 available points. However, to earn 100% the threshold is 12 points. (Therefore, once you hit 12 points, you can stop. There is no extra credit for exceeding this threshold.)

Exercise ordering: Each exercise builds logically on previous exercises, but you may solve them in any order. That is, if you can't solve an exercise, you can still move on and try the next one. Use this to your advantage, as the exercises are not necessarily ordered in terms of difficulty. Higher point values generally indicate more difficult exercises.

Demo cells: Code cells starting with the comment ### define demo inputs load results from prior exercises applied to the entire data set and use those to build demo inputs. These must be run for subsequent demos to work properly, but they do not affect the test cells. The data loaded in these cells may be rather large (at least in terms of human readability). You are free to print or otherwise use Python to explore them, but we did not print them in the starter code.

Debugging your code: Right before each exercise test cell, there is a block of text explaining the variables available to you for debugging. You may use these to test your code and can print/display them as needed (careful when printing large objects, you may want to print the head or chunks of rows at a time).

Exercise point breakdown:

  • Exercise 0: 3 point(s)
  • Exercise 1: 2 point(s)
  • Exercise 2: 1 point(s)
  • Exercise 3: 2 point(s)
  • Exercise 4: 3 point(s)
  • Exercise 5: 3 point(s)
  • Exercise 6: 1 point(s)
  • Exercise 7: 2 point(s)
  • Exercise 8: 2 point(s)

Final reminders:

  • Submit after every exercise
  • Review the generated grade report after you submit to see what errors were returned
  • Stay calm, skip problems as needed, and take short breaks at your leisure

Scenario (don't dwell on this)

You have just been hired by the hot new startup Spot-i-flix-ify (this is a fictional company which will offer video and audio streaming services) as a Data Scientist. This is a small startup so you have to "wear many different hats," so to speak. Your first task on the job is to set up their data warehousing so that they can capture a historical record of their operations for analysis later. The operational database (which someone else has already set up) only contains the current state of the operation to maintain maximum efficiency while performing tasks like adding new customers, changing services, applying promotions, etc. It will not contain any history and is not intended have complex queries run against it.

While this is a fictional company and simulation data, there is a real-world use case for the processes developed in this notebook.

Data (Don't dwell on this. The structures you are working with will be explained in each exercise.)

You are working with four tables:

  • customers - Center of the "star" schema. Primary Key: id.
    • customers.id - a unique identifier for an individual customer.
    • customers.paid - ('True'|'False') - indicates whether a customer has paid their bill for their upcoming month of service.
  • prices - The prices of the services offered by Spot-i-flix-ify. Primary Key: service, tier, promo
    • prices.service - Name of the sevice
    • prices.tier - Tier of the service. A service can be offered in several tiers. Higher tiers give customers more features.
    • prices.promo - Promotion which can be applied to a service/tier combination to offer a discount to customers.
    • prices.price - The price of a particular service/tier/promo combination.
  • services - Services which each customer is subscribed. Primary Key: cust_id, service; Foreign Keys: cust_id references customers.id, (service, tier) references (prices.service, prices.tier)
    • services.cust_id - id of the customer associated with this subscription.
    • services.service - name of service associated with this subscription.
    • services.tier - tier of service associated with a subscription.
  • promos - All promos which a customer has ever used for any service. This historical information is required to prevent customers from using the same promo twice.
    • cust_id - id of a customer associated with a particular record.
    • service - service which a customer used a particular promo on.
    • promo - name of the promo associated with a particular record.
    • time_left - number of remaining months for which the promo price is applied to a service for the customer. If all promos associated with a cust_id/service pair have 0 months left. The "base" promo is applied to the customer for that service.

On data types

These tables are made available to you in a staging environment as Pandas DataFrame objects. All columns in all of the DataFrames are strings (even the columns where you would expect other data types).

On SQL

We used Pandas exclusively in developing this exam, however some exercise are solvable using SQL. In the cell below we have included the function dfs_to_conn which can be used to create in-memory database connections. If you pass in a dictionary mapping table names to DataFrames, dfs_to_conn will return a sqlite 3 connection with all of the data in the DataFrames available under the names given as keys. You are also free to write to the in-memory database by creating tables, inserting/deleting/updating records, etc. Anything that SQLite allows should work!

Example:

my_df = pd.DataFrame({'A':[1,2,3], 'B': [4,5,6], 'C':['x', 'y', 'z']})
print(my_df)
#    A  B  C
# 0  1  4  x
# 1  2  5  y
# 2  3  6  z
conn = dfs_to_conn({'my_table': my_df})
cur = conn.cursor()
cur.execute('select A, B, C from my_table')
result = cur.fetchall()
conn.close() 
print(result) # list of tuples, each tuple is a row
#[(1, 4, 'x'), (2, 5, 'y'), (3, 6, 'z')]
In [3]:
### Global Imports
###
### AUTOGRADER TEST - DO NOT REMOVE
###
import pandas as pd
import time
overall_start = time.time()

def dfs_to_conn(conn_dfs, index=False):
    import sqlite3
    conn = sqlite3.connect(':memory:')
    for table_name, df in conn_dfs.items():
        df.to_sql(table_name, conn, if_exists='replace', index=index)
    return conn

Exercise 0 - (3 Points):

Motivation (Don't dwell on this):
The business logic behind the database requires all promos which a customer has ever participated in be stored in the "live" business data in order to prevent a customer from using the same promotion twice. However, for keeping the historical record, the data consumers (i.e. your bosses) are only interested in seeing which promotion is actually being applied to a customer's bill. We need to extract this information from the promos table.

Requirements:
Define get_active_promos(promos). The input promos is a DataFrame with columns as described in the promos table above. These are the columns/descriptions:

  • cust_id - id of a single customer.
  • service - a service where the customer has participated in a promo.
  • promo - name of a promo in which a customer has participated for the associated service.
  • time_left - the time the customer has left on the promo.

Note: There may be many records in promos with the same cust_id/service combination. However, at most one such record will have a time_left value other than '0'.

Your function should return a new DataFrame, active_promos derived from promos with the schema outlined below. There should be exactly 1 record in active_promos for each unique combination of cust_id/service found in promos.

active_promos - the promotion which is actually applied to each customer for a particular service

  • 'cust_id' - identifies an individual customer.
  • 'service' - identifies a service for which the customer has an active promotion. The customer may not actually be subscribed to the service!
  • 'promo' - the active promo for the cust_id/service pair.
    • If 'time_left' is '0' for all records associated with the cust_id/service pair in promos, this column should have a value of 'base'.
    • If there is a record associated with a non-zero 'time_left', this column should have the 'promo' from that record.
In [4]:
### Define demo inputs

demo_promos_ex0 = pd.DataFrame([
{'cust_id': '0', 'promo': 'promo_1', 'service': 'audio', 'time_left': '5'},
{'cust_id': '0', 'promo': 'promo_3', 'service': 'audio', 'time_left': '0'},
{'cust_id': '0', 'promo': 'base', 'service': 'audio', 'time_left': '0'},
{'cust_id': '0', 'promo': 'promo_3', 'service': 'video', 'time_left': '0'},
{'cust_id': '0', 'promo': 'promo_1', 'service': 'video', 'time_left': '0'},
{'cust_id': '0', 'promo': 'base', 'service': 'video', 'time_left': '0'},
{'cust_id': '1', 'promo': 'promo_3', 'service': 'audio', 'time_left': '0'},
{'cust_id': '1', 'promo': 'promo_1', 'service': 'audio', 'time_left': '0'},
{'cust_id': '1', 'promo': 'base', 'service': 'audio', 'time_left': '0'},
{'cust_id': '1', 'promo': 'promo_3', 'service': 'video', 'time_left': '0'},
{'cust_id': '1', 'promo': 'promo_1',  'service': 'video',  'time_left': '4'},
{'cust_id': '1', 'promo': 'base', 'service': 'video', 'time_left': '0'}]
)
demo_promos_ex0
Out[4]:
cust_id promo service time_left
0 0 promo_1 audio 5
1 0 promo_3 audio 0
2 0 base audio 0
3 0 promo_3 video 0
4 0 promo_1 video 0
5 0 base video 0
6 1 promo_3 audio 0
7 1 promo_1 audio 0
8 1 base audio 0
9 1 promo_3 video 0
10 1 promo_1 video 4
11 1 base video 0
The demo included in the solution cell below should display the following output: ``` cust_id promo service 0 0 promo_1 audio 1 0 base video 2 1 base audio 3 1 promo_1 video ```
In [19]:
### Exercise 0 solution
def get_active_promos(promos):
    ###
    ### YOUR CODE HERE
    ###
    
    # grouped promos df by cust_id and service
    # max of time_left for each group
    # if the max is 0, then promo = "base"
    # otherwise, promo = the promo associated with max time_left
    # return this in a df
    
    def get_cust_service(group):
        #get max time_left
        
        max_time = max(group['time_left'].astype(int))
        
        #get the id of the row w/ max time_left
        idx = group['time_left'].astype(int).idxmax()
        
        row = {
            'cust_id': group.loc[idx, 'cust_id'],
            'promo': group.loc[idx, 'promo'],
            'service': group.loc[idx, 'service']
        }
        if max_time == 0:
            row['promo'] = 'base'
        return pd.Series(row)
    
    grouped = promos.groupby(['cust_id', 'service'], as_index=False)
    grouped = grouped.apply(get_cust_service)
    display(grouped)
    return grouped
    
    
### demo function call
print(get_active_promos(demo_promos_ex0))
cust_id promo service time_left
0 0 promo_1 audio 5
1 0 promo_3 audio 0
2 0 base audio 0
cust_id promo service time_left
3 0 promo_3 video 0
4 0 promo_1 video 0
5 0 base video 0
cust_id promo service time_left
6 1 promo_3 audio 0
7 1 promo_1 audio 0
8 1 base audio 0
cust_id promo service time_left
9 1 promo_3 video 0
10 1 promo_1 video 4
11 1 base video 0
cust_id promo service
0 0 promo_1 audio
1 0 base video
2 1 base audio
3 1 promo_1 video
  cust_id    promo service
0       0  promo_1   audio
1       0     base   video
2       1     base   audio
3       1  promo_1   video

The cell below will test your solution for Exercise 0. The testing variables will be available for debugging under the following names in a dictionary format.

  • input_vars - Input variables for your solution.
  • original_input_vars - Copy of input variables from prior to running your solution. These should be the same as input_vars - otherwise the inputs were modified by your solution.
  • returned_output_vars - Outputs returned by your solution.
  • true_output_vars - The expected output. This should "match" returned_output_vars based on the question requirements - otherwise, your solution is not returning the correct output.
In [12]:
### test_cell_ex0
exercise_start = time.time()
###
### AUTOGRADER TEST - DO NOT REMOVE
###
from tester_fw.testers import Tester

conf = {
    'case_file':'tc_0', 
    'func': get_active_promos, # replace this with the function defined above
    'inputs':{ # input config dict. keys are parameter names
        'promos':{
            'dtype':'df', # data type of param.
            'check_modified':True,
        }
    },
    'outputs':{
        'output_0':{
            'index':0,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': False, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        }
    }
}
tester = Tester(conf, key=b'6IRWMcPsVIAZqzDJnPgv_MfUZsxqo4Utjm2Favidv-A=', path='resource/asnlib/publicdata/')
for _ in range(70):
    try:
        tester.run_test()
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
    except:
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
        raise

###
### AUTOGRADER TEST - DO NOT REMOVE
###
exercise_end = time.time()
print(f"This test executed in {(pd.to_datetime(exercise_end, unit='s') - pd.to_datetime(exercise_start, unit='s')).seconds} seconds")
print('Passed! Please submit.')
cust_id promo service
0 0 promo_4 audio
1 0 base video
2 1 base audio
3 1 base video
4 2 promo_1 audio
5 2 promo_2 video
6 3 promo_2 audio
7 3 base video
8 4 base audio
9 4 base video
10 5 base audio
11 5 promo_3 video
12 6 base audio
13 6 promo_2 video
14 7 promo_3 audio
15 7 promo_3 video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 base video
4 10 base audio
5 10 base video
6 2 base audio
7 2 promo_4 video
8 3 base audio
9 3 promo_2 video
10 4 base audio
11 4 promo_2 video
12 5 base audio
13 5 base video
14 6 promo_3 audio
15 6 promo_4 video
16 7 promo_5 audio
17 7 base video
18 8 promo_1 audio
19 8 promo_5 video
20 9 promo_3 audio
21 9 promo_3 video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 promo_3 video
4 10 base audio
5 10 base video
6 11 promo_2 audio
7 11 base video
8 12 base audio
9 12 base video
10 2 base audio
11 2 promo_3 video
12 3 base audio
13 3 base video
14 4 base audio
15 4 promo_5 video
16 5 base audio
17 5 base video
18 6 base audio
19 6 promo_1 video
20 7 promo_2 audio
21 7 base video
22 8 base audio
23 8 promo_5 video
24 9 promo_2 audio
25 9 base video
cust_id promo service
0 0 promo_4 audio
1 0 promo_2 video
2 1 base audio
3 1 base video
4 10 promo_1 audio
5 10 promo_4 video
6 11 base audio
7 11 base video
8 12 promo_2 audio
9 12 promo_4 video
10 2 base audio
11 2 base video
12 3 promo_1 audio
13 3 base video
14 4 promo_1 audio
15 4 base video
16 5 base audio
17 5 promo_1 video
18 6 base audio
19 6 promo_3 video
20 7 promo_4 audio
21 7 promo_5 video
22 8 promo_2 audio
23 8 base video
24 9 promo_4 audio
25 9 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_2 audio
3 1 promo_2 video
4 10 base audio
5 10 base video
6 2 base audio
7 2 promo_1 video
8 3 base audio
9 3 promo_1 video
10 4 promo_1 audio
11 4 promo_2 video
12 5 base audio
13 5 base video
14 6 promo_1 audio
15 6 base video
16 7 base audio
17 7 promo_3 video
18 8 base audio
19 8 promo_1 video
20 9 base audio
21 9 promo_5 video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_1 audio
3 1 base video
4 2 promo_5 audio
5 2 promo_4 video
6 3 base audio
7 3 promo_2 video
8 4 base audio
9 4 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 promo_3 video
4 10 promo_1 audio
5 10 promo_2 video
6 11 promo_2 audio
7 11 promo_5 video
8 12 base audio
9 12 base video
10 13 base audio
11 13 base video
12 14 promo_3 audio
13 14 base video
14 2 promo_2 audio
15 2 base video
16 3 base audio
17 3 promo_4 video
18 4 base audio
19 4 base video
20 5 promo_3 audio
21 5 promo_3 video
22 6 promo_1 audio
23 6 base video
24 7 base audio
25 7 promo_5 video
26 8 base audio
27 8 base video
28 9 promo_1 audio
29 9 promo_4 video
cust_id promo service
0 0 promo_4 audio
1 0 promo_4 video
2 1 base audio
3 1 base video
4 2 promo_1 audio
5 2 promo_2 video
6 3 base audio
7 3 base video
8 4 base audio
9 4 promo_1 video
cust_id promo service
0 0 promo_1 audio
1 0 base video
2 1 base audio
3 1 promo_5 video
4 2 base audio
5 2 base video
6 3 base audio
7 3 base video
8 4 base audio
9 4 promo_2 video
10 5 promo_2 audio
11 5 promo_1 video
12 6 base audio
13 6 base video
14 7 base audio
15 7 promo_3 video
16 8 base audio
17 8 promo_5 video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 base video
4 10 promo_5 audio
5 10 promo_5 video
6 11 base audio
7 11 base video
8 2 base audio
9 2 base video
10 3 base audio
11 3 base video
12 4 base audio
13 4 promo_5 video
14 5 base audio
15 5 base video
16 6 base audio
17 6 base video
18 7 base audio
19 7 base video
20 8 base audio
21 8 base video
22 9 base audio
23 9 base video
cust_id promo service
0 0 promo_1 audio
1 0 base video
2 1 base audio
3 1 promo_5 video
4 2 promo_1 audio
5 2 base video
6 3 base audio
7 3 promo_3 video
8 4 base audio
9 4 base video
cust_id promo service
0 0 promo_1 audio
1 0 promo_4 video
2 1 base audio
3 1 base video
4 10 base audio
5 10 promo_3 video
6 11 promo_4 audio
7 11 promo_1 video
8 12 promo_4 audio
9 12 promo_5 video
10 13 promo_3 audio
11 13 promo_5 video
12 2 base audio
13 2 base video
14 3 base audio
15 3 promo_2 video
16 4 base audio
17 4 base video
18 5 promo_4 audio
19 5 base video
20 6 promo_4 audio
21 6 base video
22 7 base audio
23 7 base video
24 8 promo_2 audio
25 8 promo_3 video
26 9 promo_5 audio
27 9 promo_4 video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 promo_3 video
4 10 base audio
5 10 base video
6 11 promo_2 audio
7 11 base video
8 12 base audio
9 12 base video
10 2 base audio
11 2 promo_3 video
12 3 base audio
13 3 base video
14 4 base audio
15 4 promo_5 video
16 5 base audio
17 5 base video
18 6 base audio
19 6 promo_1 video
20 7 promo_2 audio
21 7 base video
22 8 base audio
23 8 promo_5 video
24 9 promo_2 audio
25 9 base video
cust_id promo service
0 0 base audio
1 0 promo_2 video
2 1 promo_4 audio
3 1 base video
4 2 promo_2 audio
5 2 base video
6 3 promo_1 audio
7 3 base video
8 4 promo_5 audio
9 4 base video
10 5 promo_1 audio
11 5 promo_2 video
12 6 base audio
13 6 base video
14 7 promo_3 audio
15 7 promo_1 video
16 8 promo_4 audio
17 8 base video
cust_id promo service
0 0 promo_5 audio
1 0 base video
2 1 base audio
3 1 base video
4 10 promo_2 audio
5 10 promo_4 video
6 11 promo_4 audio
7 11 base video
8 12 base audio
9 12 base video
10 13 base audio
11 13 promo_5 video
12 2 base audio
13 2 base video
14 3 base audio
15 3 promo_2 video
16 4 promo_5 audio
17 4 base video
18 5 base audio
19 5 base video
20 6 base audio
21 6 base video
22 7 base audio
23 7 promo_3 video
24 8 promo_1 audio
25 8 base video
26 9 base audio
27 9 promo_4 video
cust_id promo service
0 0 base audio
1 0 promo_3 video
2 1 base audio
3 1 base video
4 2 promo_2 audio
5 2 base video
6 3 promo_5 audio
7 3 promo_3 video
8 4 promo_1 audio
9 4 base video
10 5 promo_1 audio
11 5 base video
cust_id promo service
0 0 promo_4 audio
1 0 promo_4 video
2 1 base audio
3 1 base video
4 10 base audio
5 10 promo_5 video
6 11 base audio
7 11 promo_5 video
8 12 base audio
9 12 base video
10 2 promo_4 audio
11 2 base video
12 3 base audio
13 3 base video
14 4 promo_1 audio
15 4 base video
16 5 promo_5 audio
17 5 base video
18 6 base audio
19 6 base video
20 7 base audio
21 7 promo_3 video
22 8 promo_2 audio
23 8 promo_5 video
24 9 promo_4 audio
25 9 base video
cust_id promo service
0 0 promo_4 audio
1 0 promo_1 video
2 1 base audio
3 1 base video
4 2 base audio
5 2 promo_1 video
6 3 promo_3 audio
7 3 base video
8 4 base audio
9 4 promo_1 video
10 5 base audio
11 5 base video
12 6 base audio
13 6 base video
14 7 base audio
15 7 base video
16 8 base audio
17 8 base video
18 9 base audio
19 9 base video
cust_id promo service
0 0 promo_4 audio
1 0 promo_1 video
2 1 base audio
3 1 base video
4 2 base audio
5 2 promo_1 video
6 3 promo_3 audio
7 3 base video
8 4 base audio
9 4 promo_1 video
10 5 base audio
11 5 base video
12 6 base audio
13 6 base video
14 7 base audio
15 7 base video
16 8 base audio
17 8 base video
18 9 base audio
19 9 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 base video
4 2 base audio
5 2 base video
6 3 base audio
7 3 promo_1 video
8 4 base audio
9 4 base video
cust_id promo service
0 0 base audio
1 0 promo_4 video
2 1 promo_2 audio
3 1 promo_5 video
4 10 promo_2 audio
5 10 promo_4 video
6 11 promo_4 audio
7 11 promo_3 video
8 12 base audio
9 12 base video
10 2 base audio
11 2 base video
12 3 base audio
13 3 promo_2 video
14 4 base audio
15 4 base video
16 5 promo_3 audio
17 5 base video
18 6 base audio
19 6 base video
20 7 base audio
21 7 base video
22 8 base audio
23 8 promo_5 video
24 9 promo_3 audio
25 9 promo_3 video
cust_id promo service
0 0 promo_4 audio
1 0 promo_3 video
2 1 base audio
3 1 base video
4 10 base audio
5 10 base video
6 11 base audio
7 11 base video
8 2 promo_1 audio
9 2 base video
10 3 promo_2 audio
11 3 base video
12 4 base audio
13 4 base video
14 5 promo_2 audio
15 5 promo_3 video
16 6 base audio
17 6 base video
18 7 promo_2 audio
19 7 base video
20 8 promo_3 audio
21 8 base video
22 9 base audio
23 9 base video
cust_id promo service
0 0 base audio
1 0 promo_5 video
2 1 base audio
3 1 base video
4 2 base audio
5 2 base video
6 3 base audio
7 3 promo_1 video
8 4 promo_5 audio
9 4 promo_5 video
10 5 promo_4 audio
11 5 promo_2 video
12 6 base audio
13 6 base video
14 7 base audio
15 7 base video
cust_id promo service
0 0 promo_4 audio
1 0 promo_3 video
2 1 base audio
3 1 base video
4 10 base audio
5 10 base video
6 11 base audio
7 11 base video
8 2 promo_1 audio
9 2 base video
10 3 promo_2 audio
11 3 base video
12 4 base audio
13 4 base video
14 5 promo_2 audio
15 5 promo_3 video
16 6 base audio
17 6 base video
18 7 promo_2 audio
19 7 base video
20 8 promo_3 audio
21 8 base video
22 9 base audio
23 9 base video
cust_id promo service
0 0 base audio
1 0 promo_2 video
2 1 base audio
3 1 base video
4 2 base audio
5 2 base video
6 3 promo_2 audio
7 3 promo_5 video
8 4 base audio
9 4 base video
10 5 promo_3 audio
11 5 base video
cust_id promo service
0 0 base audio
1 0 promo_5 video
2 1 base audio
3 1 base video
4 2 base audio
5 2 base video
6 3 base audio
7 3 promo_1 video
8 4 promo_5 audio
9 4 promo_5 video
10 5 promo_4 audio
11 5 promo_2 video
12 6 base audio
13 6 base video
14 7 base audio
15 7 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_1 audio
3 1 base video
4 2 promo_5 audio
5 2 promo_4 video
6 3 base audio
7 3 promo_2 video
8 4 base audio
9 4 base video
cust_id promo service
0 0 base audio
1 0 promo_3 video
2 1 promo_4 audio
3 1 promo_5 video
4 10 promo_5 audio
5 10 promo_3 video
6 2 promo_5 audio
7 2 base video
8 3 base audio
9 3 base video
10 4 base audio
11 4 base video
12 5 base audio
13 5 base video
14 6 base audio
15 6 base video
16 7 base audio
17 7 promo_2 video
18 8 promo_2 audio
19 8 promo_4 video
20 9 base audio
21 9 base video
cust_id promo service
0 0 promo_3 audio
1 0 promo_5 video
2 1 base audio
3 1 promo_5 video
4 10 base audio
5 10 promo_2 video
6 11 base audio
7 11 base video
8 12 promo_1 audio
9 12 promo_2 video
10 13 base audio
11 13 promo_3 video
12 2 base audio
13 2 promo_1 video
14 3 promo_1 audio
15 3 base video
16 4 promo_1 audio
17 4 base video
18 5 base audio
19 5 base video
20 6 base audio
21 6 promo_5 video
22 7 promo_1 audio
23 7 promo_4 video
24 8 promo_3 audio
25 8 base video
26 9 base audio
27 9 base video
cust_id promo service
0 0 base audio
1 0 promo_3 video
2 1 base audio
3 1 base video
4 10 base audio
5 10 base video
6 11 base audio
7 11 base video
8 2 base audio
9 2 promo_4 video
10 3 promo_5 audio
11 3 promo_4 video
12 4 base audio
13 4 base video
14 5 promo_2 audio
15 5 promo_2 video
16 6 base audio
17 6 base video
18 7 base audio
19 7 promo_2 video
20 8 promo_3 audio
21 8 promo_4 video
22 9 promo_2 audio
23 9 base video
cust_id promo service
0 0 promo_1 audio
1 0 promo_4 video
2 1 promo_5 audio
3 1 base video
4 10 promo_1 audio
5 10 base video
6 11 promo_1 audio
7 11 base video
8 2 base audio
9 2 base video
10 3 base audio
11 3 promo_5 video
12 4 promo_1 audio
13 4 base video
14 5 promo_5 audio
15 5 base video
16 6 promo_3 audio
17 6 base video
18 7 base audio
19 7 promo_3 video
20 8 promo_1 audio
21 8 promo_1 video
22 9 base audio
23 9 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 base video
4 2 base audio
5 2 base video
6 3 promo_4 audio
7 3 base video
8 4 base audio
9 4 base video
10 5 promo_4 audio
11 5 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 promo_1 video
4 2 promo_2 audio
5 2 promo_3 video
6 3 base audio
7 3 promo_1 video
8 4 promo_4 audio
9 4 base video
10 5 base audio
11 5 base video
12 6 promo_5 audio
13 6 promo_3 video
14 7 promo_5 audio
15 7 promo_2 video
16 8 base audio
17 8 base video
18 9 base audio
19 9 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_1 audio
3 1 promo_3 video
4 2 base audio
5 2 base video
6 3 promo_4 audio
7 3 base video
8 4 base audio
9 4 base video
10 5 base audio
11 5 promo_1 video
12 6 base audio
13 6 base video
14 7 base audio
15 7 promo_3 video
16 8 base audio
17 8 promo_2 video
18 9 base audio
19 9 base video
cust_id promo service
0 0 promo_1 audio
1 0 promo_4 video
2 1 promo_5 audio
3 1 base video
4 10 promo_1 audio
5 10 base video
6 11 promo_1 audio
7 11 base video
8 2 base audio
9 2 base video
10 3 base audio
11 3 promo_5 video
12 4 promo_1 audio
13 4 base video
14 5 promo_5 audio
15 5 base video
16 6 promo_3 audio
17 6 base video
18 7 base audio
19 7 promo_3 video
20 8 promo_1 audio
21 8 promo_1 video
22 9 base audio
23 9 base video
cust_id promo service
0 0 base audio
1 0 promo_2 video
2 1 promo_4 audio
3 1 base video
4 2 promo_2 audio
5 2 base video
6 3 promo_1 audio
7 3 base video
8 4 promo_5 audio
9 4 base video
10 5 promo_1 audio
11 5 promo_2 video
12 6 base audio
13 6 base video
14 7 promo_3 audio
15 7 promo_1 video
16 8 promo_4 audio
17 8 base video
cust_id promo service
0 0 promo_5 audio
1 0 base video
2 1 base audio
3 1 promo_3 video
4 10 base audio
5 10 base video
6 2 base audio
7 2 base video
8 3 base audio
9 3 base video
10 4 promo_1 audio
11 4 base video
12 5 promo_5 audio
13 5 base video
14 6 base audio
15 6 base video
16 7 base audio
17 7 promo_4 video
18 8 base audio
19 8 base video
20 9 promo_5 audio
21 9 promo_2 video
cust_id promo service
0 0 base audio
1 0 promo_1 video
2 1 base audio
3 1 base video
4 2 promo_1 audio
5 2 base video
6 3 promo_3 audio
7 3 promo_4 video
8 4 promo_2 audio
9 4 base video
10 5 promo_2 audio
11 5 base video
12 6 promo_2 audio
13 6 promo_2 video
14 7 base audio
15 7 base video
16 8 base audio
17 8 promo_2 video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_1 audio
3 1 base video
4 10 base audio
5 10 promo_4 video
6 11 promo_3 audio
7 11 promo_1 video
8 12 promo_2 audio
9 12 base video
10 2 base audio
11 2 promo_1 video
12 3 promo_5 audio
13 3 promo_3 video
14 4 promo_1 audio
15 4 promo_1 video
16 5 promo_5 audio
17 5 base video
18 6 base audio
19 6 base video
20 7 base audio
21 7 promo_5 video
22 8 base audio
23 8 base video
24 9 promo_3 audio
25 9 base video
cust_id promo service
0 0 promo_5 audio
1 0 base video
2 1 base audio
3 1 base video
4 10 base audio
5 10 promo_3 video
6 11 promo_2 audio
7 11 base video
8 12 base audio
9 12 base video
10 13 promo_4 audio
11 13 promo_4 video
12 14 base audio
13 14 promo_5 video
14 2 base audio
15 2 base video
16 3 base audio
17 3 promo_1 video
18 4 promo_3 audio
19 4 base video
20 5 base audio
21 5 base video
22 6 base audio
23 6 promo_5 video
24 7 promo_1 audio
25 7 base video
26 8 base audio
27 8 promo_5 video
28 9 base audio
29 9 promo_4 video
cust_id promo service
0 0 base audio
1 0 promo_4 video
2 1 base audio
3 1 promo_5 video
4 2 promo_2 audio
5 2 base video
6 3 base audio
7 3 base video
8 4 promo_2 audio
9 4 promo_2 video
10 5 base audio
11 5 promo_5 video
12 6 promo_1 audio
13 6 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_1 audio
3 1 promo_5 video
4 10 base audio
5 10 base video
6 11 base audio
7 11 base video
8 12 base audio
9 12 promo_4 video
10 2 base audio
11 2 promo_3 video
12 3 promo_4 audio
13 3 promo_1 video
14 4 base audio
15 4 base video
16 5 promo_1 audio
17 5 promo_3 video
18 6 base audio
19 6 base video
20 7 promo_4 audio
21 7 promo_3 video
22 8 base audio
23 8 base video
24 9 base audio
25 9 base video
cust_id promo service
0 0 base audio
1 0 promo_3 video
2 1 promo_2 audio
3 1 base video
4 2 promo_5 audio
5 2 promo_3 video
6 3 base audio
7 3 promo_2 video
8 4 base audio
9 4 base video
10 5 promo_2 audio
11 5 base video
12 6 base audio
13 6 base video
14 7 promo_3 audio
15 7 promo_1 video
16 8 base audio
17 8 base video
18 9 base audio
19 9 promo_1 video
cust_id promo service
0 0 base audio
1 0 promo_3 video
2 1 base audio
3 1 promo_4 video
4 2 base audio
5 2 base video
6 3 base audio
7 3 promo_4 video
8 4 promo_3 audio
9 4 promo_3 video
10 5 promo_3 audio
11 5 base video
12 6 base audio
13 6 promo_2 video
14 7 promo_2 audio
15 7 promo_1 video
16 8 promo_4 audio
17 8 base video
18 9 base audio
19 9 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 base video
4 2 promo_1 audio
5 2 base video
6 3 promo_3 audio
7 3 promo_3 video
8 4 base audio
9 4 base video
10 5 promo_2 audio
11 5 promo_2 video
12 6 base audio
13 6 promo_1 video
14 7 promo_3 audio
15 7 promo_2 video
16 8 promo_2 audio
17 8 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 promo_5 video
4 2 promo_5 audio
5 2 base video
6 3 base audio
7 3 base video
8 4 base audio
9 4 base video
10 5 base audio
11 5 base video
12 6 promo_3 audio
13 6 promo_5 video
14 7 promo_3 audio
15 7 promo_4 video
cust_id promo service
0 0 promo_1 audio
1 0 promo_5 video
2 1 base audio
3 1 promo_4 video
4 2 promo_5 audio
5 2 base video
6 3 base audio
7 3 base video
8 4 base audio
9 4 promo_5 video
10 5 base audio
11 5 base video
12 6 promo_1 audio
13 6 base video
14 7 promo_3 audio
15 7 base video
16 8 promo_5 audio
17 8 base video
18 9 base audio
19 9 base video
cust_id promo service
0 0 promo_1 audio
1 0 promo_5 video
2 1 base audio
3 1 promo_4 video
4 2 promo_5 audio
5 2 base video
6 3 base audio
7 3 base video
8 4 base audio
9 4 promo_5 video
10 5 base audio
11 5 base video
12 6 promo_1 audio
13 6 base video
14 7 promo_3 audio
15 7 base video
16 8 promo_5 audio
17 8 base video
18 9 base audio
19 9 base video
cust_id promo service
0 0 base audio
1 0 promo_5 video
2 1 base audio
3 1 base video
4 2 promo_1 audio
5 2 promo_4 video
6 3 promo_5 audio
7 3 promo_5 video
8 4 base audio
9 4 promo_3 video
10 5 promo_4 audio
11 5 promo_4 video
12 6 promo_5 audio
13 6 promo_1 video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_1 audio
3 1 base video
4 2 base audio
5 2 base video
6 3 promo_4 audio
7 3 promo_1 video
8 4 base audio
9 4 promo_4 video
10 5 base audio
11 5 promo_5 video
12 6 promo_2 audio
13 6 base video
14 7 promo_3 audio
15 7 base video
16 8 promo_5 audio
17 8 promo_2 video
18 9 promo_3 audio
19 9 base video
cust_id promo service
0 0 promo_3 audio
1 0 base video
2 1 promo_5 audio
3 1 promo_5 video
4 2 promo_1 audio
5 2 base video
6 3 base audio
7 3 promo_3 video
8 4 base audio
9 4 base video
10 5 promo_1 audio
11 5 base video
cust_id promo service
0 0 promo_4 audio
1 0 promo_2 video
2 1 base audio
3 1 promo_3 video
4 10 base audio
5 10 promo_1 video
6 11 base audio
7 11 promo_3 video
8 12 promo_1 audio
9 12 base video
10 13 promo_2 audio
11 13 base video
12 2 promo_5 audio
13 2 promo_4 video
14 3 promo_2 audio
15 3 base video
16 4 base audio
17 4 promo_1 video
18 5 promo_1 audio
19 5 promo_2 video
20 6 base audio
21 6 base video
22 7 promo_1 audio
23 7 promo_5 video
24 8 base audio
25 8 base video
26 9 base audio
27 9 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_3 audio
3 1 promo_3 video
4 10 base audio
5 10 promo_2 video
6 2 promo_2 audio
7 2 base video
8 3 promo_4 audio
9 3 base video
10 4 base audio
11 4 base video
12 5 base audio
13 5 promo_1 video
14 6 promo_2 audio
15 6 promo_1 video
16 7 base audio
17 7 promo_3 video
18 8 base audio
19 8 base video
20 9 base audio
21 9 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_1 audio
3 1 promo_5 video
4 10 base audio
5 10 base video
6 11 base audio
7 11 base video
8 12 base audio
9 12 promo_4 video
10 2 base audio
11 2 promo_3 video
12 3 promo_4 audio
13 3 promo_1 video
14 4 base audio
15 4 base video
16 5 promo_1 audio
17 5 promo_3 video
18 6 base audio
19 6 base video
20 7 promo_4 audio
21 7 promo_3 video
22 8 base audio
23 8 base video
24 9 base audio
25 9 base video
cust_id promo service
0 0 promo_4 audio
1 0 promo_2 video
2 1 base audio
3 1 base video
4 10 promo_1 audio
5 10 promo_4 video
6 11 base audio
7 11 base video
8 12 promo_2 audio
9 12 promo_4 video
10 2 base audio
11 2 base video
12 3 promo_1 audio
13 3 base video
14 4 promo_1 audio
15 4 base video
16 5 base audio
17 5 promo_1 video
18 6 base audio
19 6 promo_3 video
20 7 promo_4 audio
21 7 promo_5 video
22 8 promo_2 audio
23 8 base video
24 9 promo_4 audio
25 9 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 base video
4 2 promo_1 audio
5 2 base video
6 3 promo_3 audio
7 3 promo_3 video
8 4 base audio
9 4 base video
10 5 promo_2 audio
11 5 promo_2 video
12 6 base audio
13 6 promo_1 video
14 7 promo_3 audio
15 7 promo_2 video
16 8 promo_2 audio
17 8 base video
cust_id promo service
0 0 base audio
1 0 promo_3 video
2 1 promo_4 audio
3 1 promo_2 video
4 2 base audio
5 2 promo_3 video
6 3 promo_5 audio
7 3 promo_4 video
8 4 base audio
9 4 promo_2 video
10 5 base audio
11 5 base video
12 6 base audio
13 6 base video
14 7 base audio
15 7 base video
cust_id promo service
0 0 promo_3 audio
1 0 promo_5 video
2 1 base audio
3 1 promo_4 video
4 2 base audio
5 2 promo_4 video
6 3 base audio
7 3 base video
8 4 base audio
9 4 promo_3 video
10 5 base audio
11 5 promo_4 video
12 6 promo_2 audio
13 6 promo_2 video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_2 audio
3 1 base video
4 10 base audio
5 10 promo_3 video
6 11 base audio
7 11 base video
8 12 base audio
9 12 base video
10 13 base audio
11 13 base video
12 14 base audio
13 14 promo_1 video
14 2 promo_2 audio
15 2 base video
16 3 base audio
17 3 base video
18 4 base audio
19 4 promo_4 video
20 5 promo_2 audio
21 5 base video
22 6 base audio
23 6 base video
24 7 promo_2 audio
25 7 promo_1 video
26 8 promo_5 audio
27 8 base video
28 9 promo_1 audio
29 9 base video
cust_id promo service
0 0 base audio
1 0 promo_5 video
2 1 promo_4 audio
3 1 promo_1 video
4 2 base audio
5 2 promo_1 video
6 3 base audio
7 3 promo_3 video
8 4 promo_2 audio
9 4 promo_3 video
10 5 base audio
11 5 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 base video
4 2 base audio
5 2 base video
6 3 promo_4 audio
7 3 base video
8 4 base audio
9 4 base video
10 5 promo_4 audio
11 5 base video
cust_id promo service
0 0 promo_5 audio
1 0 base video
2 1 base audio
3 1 promo_3 video
4 10 base audio
5 10 base video
6 2 base audio
7 2 base video
8 3 base audio
9 3 base video
10 4 promo_1 audio
11 4 base video
12 5 promo_5 audio
13 5 base video
14 6 base audio
15 6 base video
16 7 base audio
17 7 promo_4 video
18 8 base audio
19 8 base video
20 9 promo_5 audio
21 9 promo_2 video
cust_id promo service
0 0 promo_1 audio
1 0 base video
2 1 base audio
3 1 base video
4 2 base audio
5 2 base video
6 3 base audio
7 3 base video
8 4 promo_5 audio
9 4 promo_1 video
cust_id promo service
0 0 base audio
1 0 base video
2 1 base audio
3 1 promo_3 video
4 10 promo_1 audio
5 10 promo_2 video
6 11 promo_2 audio
7 11 promo_5 video
8 12 base audio
9 12 base video
10 13 base audio
11 13 base video
12 14 promo_3 audio
13 14 base video
14 2 promo_2 audio
15 2 base video
16 3 base audio
17 3 promo_4 video
18 4 base audio
19 4 base video
20 5 promo_3 audio
21 5 promo_3 video
22 6 promo_1 audio
23 6 base video
24 7 base audio
25 7 promo_5 video
26 8 base audio
27 8 base video
28 9 promo_1 audio
29 9 promo_4 video
cust_id promo service
0 0 promo_4 audio
1 0 base video
2 1 base audio
3 1 base video
4 2 promo_1 audio
5 2 promo_2 video
6 3 promo_2 audio
7 3 base video
8 4 base audio
9 4 base video
10 5 base audio
11 5 promo_3 video
12 6 base audio
13 6 promo_2 video
14 7 promo_3 audio
15 7 promo_3 video
cust_id promo service
0 0 promo_1 audio
1 0 base video
2 1 base audio
3 1 promo_5 video
4 2 base audio
5 2 base video
6 3 base audio
7 3 base video
8 4 base audio
9 4 promo_2 video
10 5 promo_2 audio
11 5 promo_1 video
12 6 base audio
13 6 base video
14 7 base audio
15 7 promo_3 video
16 8 base audio
17 8 promo_5 video
cust_id promo service
0 0 promo_3 audio
1 0 base video
2 1 promo_5 audio
3 1 promo_5 video
4 2 promo_1 audio
5 2 base video
6 3 base audio
7 3 promo_3 video
8 4 base audio
9 4 base video
10 5 promo_1 audio
11 5 base video
cust_id promo service
0 0 promo_3 audio
1 0 promo_5 video
2 1 base audio
3 1 promo_4 video
4 2 base audio
5 2 promo_4 video
6 3 base audio
7 3 base video
8 4 base audio
9 4 promo_3 video
10 5 base audio
11 5 promo_4 video
12 6 promo_2 audio
13 6 promo_2 video
cust_id promo service
0 0 base audio
1 0 promo_3 video
2 1 promo_4 audio
3 1 promo_5 video
4 10 promo_5 audio
5 10 promo_3 video
6 2 promo_5 audio
7 2 base video
8 3 base audio
9 3 base video
10 4 base audio
11 4 base video
12 5 base audio
13 5 base video
14 6 base audio
15 6 base video
16 7 base audio
17 7 promo_2 video
18 8 promo_2 audio
19 8 promo_4 video
20 9 base audio
21 9 base video
cust_id promo service
0 0 base audio
1 0 base video
2 1 promo_3 audio
3 1 base video
4 2 promo_3 audio
5 2 base video
6 3 base audio
7 3 base video
8 4 base audio
9 4 promo_4 video
10 5 base audio
11 5 base video
12 6 promo_4 audio
13 6 promo_2 video
14 7 base audio
15 7 base video
16 8 base audio
17 8 promo_5 video
This test executed in 2 seconds
Passed! Please submit.

Exercise 1 - (2 Points):

Motivation (Don't dwell on this):
To allow for faster updates, the business schema is somewhat normalized. To get the full picture of each service a customer is subscribed to, we have to use the relationships between the keys in each table to piece everything together. For our historical record, the requirement is a little different. We will only add records to the history. Recording the history of each normalized table is not desired as it will require more engineering to piece together. We will instead de-normalize the tables and then record the history of our de-normalized result.

Requirements:
Define the function denormalize(customers, services, active_promos, prices) which takes the DataFrame inputs which have the same structure as those in the introduction and from the result of exercise 0. See the data model diagram for the relationships between the 4 tables.

data_model

Your function should return a DataFrame df which contains the following columns:

  • id - identifies a particular customer (from customers)
  • paid - ('True'|'False') indicating whether the customer id has paid their bill (from customers)
  • service - a service which a customer is subscribed. There should be one record for each unique id/service pair (from services)
  • tier - tier of a service for the id/service pair. (from services)
  • promo - promo being applied to the id/service pair. (from active_promos)
    • Remember that a record existing with a cust_id/service combination in active_promos does not imply the customer is subscribed to that service.
  • price - price charged for the id/service pair (from prices)

    You can accomplish this task using a series of "left" merges.

In [20]:
### Define demo inputs

demo_customers_ex1 = pd.DataFrame({'id': {0: '0', 1: '1'}, 'paid': {0: 'True', 1: 'False'}})
demo_active_promos_ex1 = pd.DataFrame({'cust_id': {0: '0', 1: '0', 2: '1', 3: '1'},
 'service': {0: 'audio', 1: 'video', 2: 'audio', 3: 'video'},
 'promo': {0: 'intro', 1: 'base', 2: 'base', 3: 'intro'}})
demo_prices_ex1 = pd.DataFrame(
    {'service': {0: 'audio',  1: 'audio',  2: 'audio',  3: 'audio',  4: 'video',  5: 'video',  6: 'video',  7: 'video'},
    'tier': {0: '1', 1: '1', 2: '2', 3: '2', 4: '1', 5: '1', 6: '2', 7: '2'},
    'promo': {0: 'base', 1: 'intro', 2: 'base', 3: 'intro', 4: 'base', 5: 'intro', 6: 'base', 7: 'intro'},
    'price': {0: '8.99', 1: '5.99', 2: '12.99', 3: '9.99', 4: '10.99', 5: '8.99', 6: '15.99', 7: '11.99'}})
demo_services_ex1 = pd.DataFrame({'cust_id': {0: '0', 1: '1', 2: '1'},
 'service': {0: 'audio', 1: 'video', 2: 'audio'},
 'tier': {0: '1', 1: '1', 2: '2'}})

print('customers')
print(demo_customers_ex1)
print()
print('services')
print(demo_services_ex1)
print()
print('active_promos')
print(demo_active_promos_ex1)
print()
print('prices')
print(demo_prices_ex1)
customers
  id   paid
0  0   True
1  1  False

services
  cust_id service tier
0       0   audio    1
1       1   video    1
2       1   audio    2

active_promos
  cust_id service  promo
0       0   audio  intro
1       0   video   base
2       1   audio   base
3       1   video  intro

prices
  service tier  promo  price
0   audio    1   base   8.99
1   audio    1  intro   5.99
2   audio    2   base  12.99
3   audio    2  intro   9.99
4   video    1   base  10.99
5   video    1  intro   8.99
6   video    2   base  15.99
7   video    2  intro  11.99
The demo included in the solution cell below should display the following output: ``` id paid service tier promo price 0 0 True audio 1 intro 5.99 1 1 False video 1 intro 8.99 2 1 False audio 2 base 12.99 ```
In [27]:
### Exercise 1 solution
def denormalize(customers, services, active_promos, prices):
    ###
    ### YOUR CODE HERE
    ###
    
    # sequence of 3 left merges
    merged_1 = customers.merge(services, how='left', left_on='id', right_on='cust_id')
    #display(merged_1)
    merged_2 = merged_1.merge(active_promos, how='left', on=['cust_id', 'service'])
    display(merged_2)
    merged_3 = merged_2.merge(prices, how='left', on=['service', 'tier', 'promo'])
    #display(merged_3)
    final = merged_3.drop(columns=['cust_id'])
    return final
    
    
demo_ex1_output = denormalize(demo_customers_ex1, demo_services_ex1, demo_active_promos_ex1, demo_prices_ex1)
print(demo_ex1_output)
id paid cust_id service tier promo
0 0 True 0 audio 1 intro
1 1 False 1 video 1 intro
2 1 False 1 audio 2 base
  id   paid service tier  promo  price
0  0   True   audio    1  intro   5.99
1  1  False   video    1  intro   8.99
2  1  False   audio    2   base  12.99

The cell below will test your solution for Exercise 1. The testing variables will be available for debugging under the following names in a dictionary format.

  • input_vars - Input variables for your solution.
  • original_input_vars - Copy of input variables from prior to running your solution. These should be the same as input_vars - otherwise the inputs were modified by your solution.
  • returned_output_vars - Outputs returned by your solution.
  • true_output_vars - The expected output. This should "match" returned_output_vars based on the question requirements - otherwise, your solution is not returning the correct output.
In [26]:
### test_cell_ex1
exercise_start = time.time()
###
### AUTOGRADER TEST - DO NOT REMOVE
###
from tester_fw.testers import Tester

conf = {
    'case_file':'tc_1', 
    'func': denormalize, # replace this with the function defined above
    'inputs':{ # input config dict. keys are parameter names
        'customers':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'services':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'active_promos':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'prices':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        }
    },
    'outputs':{
        'output_0':{
            'index':0,
            'dtype':'',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': False, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        }
    }
}
tester = Tester(conf, key=b'6IRWMcPsVIAZqzDJnPgv_MfUZsxqo4Utjm2Favidv-A=', path='resource/asnlib/publicdata/')
for _ in range(70):
    try:
        tester.run_test()
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
    except:
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
        raise

###
### AUTOGRADER TEST - DO NOT REMOVE
###
exercise_end = time.time()
print(f"This test executed in {(pd.to_datetime(exercise_end, unit='s') - pd.to_datetime(exercise_start, unit='s')).seconds} seconds")
print('Passed! Please submit.')
This test executed in 5 seconds
Passed! Please submit.

Exercise 2 - (1 Points):

Motivation (Don't dwell on this):
The business in interested in determining the revenue generated from its customers (go figure!). After de-normalizing this is pretty easy to calculate. All we have to do is take the sum of the price column!

Requirements:

Define the function get_revenue(df).

The input df is a DataFrame with the same structure as the result from exercise 1. Return the total of the 'price' column. Recall from the intro that all of the data fields are strings, so you will have to explicitly cast to a float before computing the total. Round the result to 2 decimal places.

In [29]:
### Define demo inputs

demo_df_ex2 = pd.DataFrame({'id': {0: '0', 1: '2', 2: '2', 3: '3', 4: '4'},
 'paid': {0: 'True', 1: 'True', 2: 'True', 3: 'True', 4: 'True'},
 'service': {0: 'audio', 1: 'video', 2: 'audio', 3: 'audio', 4: 'video'},
 'tier': {0: '1', 1: '2', 2: '2', 3: '1', 4: '1'},
 'promo': {0: 'base', 1: 'base', 2: 'base', 3: 'base', 4: 'base'},
 'price': {0: '8.99', 1: '15.99', 2: '12.99', 3: '8.99', 4: '10.99'}})

print(demo_df_ex2)
  id  paid service tier promo  price
0  0  True   audio    1  base   8.99
1  2  True   video    2  base  15.99
2  2  True   audio    2  base  12.99
3  3  True   audio    1  base   8.99
4  4  True   video    1  base  10.99
The demo included in the solution cell below should display the following output: ``` 57.95 ```
In [32]:
### Exercise 2 solution
def get_revenue(df):
    ###
    ### YOUR CODE HERE
    ###
    total = round(df['price'].astype(float).sum(), 2)
    return total
    
    
print(get_revenue(demo_df_ex2))
57.95

The cell below will test your solution for Exercise 2. The testing variables will be available for debugging under the following names in a dictionary format.

  • input_vars - Input variables for your solution.
  • original_input_vars - Copy of input variables from prior to running your solution. These should be the same as input_vars - otherwise the inputs were modified by your solution.
  • returned_output_vars - Outputs returned by your solution.
  • true_output_vars - The expected output. This should "match" returned_output_vars based on the question requirements - otherwise, your solution is not returning the correct output.
In [33]:
### test_cell_ex2
exercise_start = time.time()
###
### AUTOGRADER TEST - DO NOT REMOVE
###
from tester_fw.testers import Tester

conf = {
    'case_file':'tc_2', 
    'func': get_revenue, # replace this with the function defined above
    'inputs':{ # input config dict. keys are parameter names
        'df':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        }
    },
    'outputs':{
        'output_0':{
            'index':0,
            'dtype':'float',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': True, # Ignored if dtype is not df
            'check_row_order': True, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        }
    }
}
tester = Tester(conf, key=b'6IRWMcPsVIAZqzDJnPgv_MfUZsxqo4Utjm2Favidv-A=', path='resource/asnlib/publicdata/')
for _ in range(70):
    try:
        tester.run_test()
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
    except:
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
        raise

###
### AUTOGRADER TEST - DO NOT REMOVE
###
exercise_end = time.time()
print(f"This test executed in {(pd.to_datetime(exercise_end, unit='s') - pd.to_datetime(exercise_start, unit='s')).seconds} seconds")
print('Passed! Please submit.')
This test executed in 3 seconds
Passed! Please submit.

Capturing Data Changes (feel free to skip reading this.)

We are going to store the history by using "type-2" journaling. This process involves scanning the business data periodically and keeping track of the first and last dates which a record existed in a particular form.

To do this we rely on the assumption that there is a "key" which identifies a particular record in the business data. The key will never change, and it can be either a single column or a combination of multiple columns. In this application it is the id and service columns. All non-key columns are subject to change. We need multiple versions of the each record, so in our journal we add columns to track the "effective date" and the "expiration date" of each version. The effective date is when the record first existed in a particular form, and the expiration date is the last date when the record existed in a particular form. By convention, the expiration date for any records which currently exist in the business data (i.e. "active records") will be '9999-12-31' (the maximum date that can be represented in YYYY-MM-DD).

We update the journal as follows:

  • Key is found in business data which does not exist in the journal (new record)
    • Add the record to the journal with the effective date as the current snapshot date and expiration date as '9999-12-31'.
  • Non-key columns are changed in the business data for a key which already exists in the journal (changed record)
    • Set the expiration date for the active record in the journal to 1 day prior to the current snapshot date.
    • Add the current record in the business data to the journal with the effective date as the current snapshot date and expiration date as '9999-12-31'.
  • A key which has an active record in the journal no longer exists in the business data (deleted record)
    • Set the expiration date for the active record in the journal to 1 day prior to the current snapshot date.

There will be exactly one record in the journal with a particular key and effective date, and there will be exactly one record with a particular key and expiration date. We can re-create a snapshot of the business data for a particular date in the past by filtering the journal to only include records where that date is inclusively between the effective and expiration dates.

The next several exercises will break down the process into digestable bits, so don't feel overwhelmed if you don't fully grasp this concept.

Exercise 3 - (2 Points):

Motivation (don't dwell on this):

The first task in our journaling process is to identify which records in the existing journal are active and which records are not. We will do so by checking the 'exp_dt' column. All records with '9999-12-31' as their expiration date are considered active. We will be rebuilding the entire journal, so we need to partition the existing journal into active and not-active records and return both parts. The active records will be compared with the business data, and the inactive records will be included in the updated journal without modification. Additionally, on the initial load, there will not be an existing journal, so we will need to create it based on the data being loaded and the desired audit columns.

Requirements:
Define partition_journal(df, audit_cols, existing_journal=None).

  • The input df is a DataFrame - we do not care about it's structure.
  • The input audit_cols is a list of strings. These are the names of audit columns used to track history in the journal. audit_cols will always include the strings 'eff_dt' and 'exp_dt'.
  • The optional input existing_journal is a DataFrame or None. If existing_journal is not None it will have all of the columns in df and all of the audit_cols as its columns.

Your function should do the following:

  • If existing_journal is None, create an empty DataFrame which has all of the columns in df and all of the audit_cols as its columns. This empty DataFrame will be used in the subsequent operations.
  • Create historical_journal which is a DataFrame containing all rows of existing_journal where 'exp_dt' is something other than '9999-12-31'.
  • Create active_journal which is a DataFrame containing all rows of existing_journal where 'exp_dt' is '9999-12-31'.
  • Return the tuple (historical_journal, active_journal) - If the existing_journal was newly created these will be two empty DataFrames with all columns present in df and all of the audit_cols.
In [34]:
### Define demo inputs

demo_df_ex3 = pd.DataFrame({'id': {0: '1', 1: '2', 2: '2'},
 'paid': {0: 'True', 1: 'True', 2: 'True'},
 'service': {0: 'audio', 1: 'video', 2: 'audio'},
 'tier': {0: '1', 1: '2', 2: '2'},
 'promo': {0: 'base', 1: 'base', 2: 'base'},
 'price': {0: '8.99', 1: '15.99', 2: '12.99'}})
demo_existing_journal_ex3 = pd.DataFrame(
    {'id': {667: '0', 668: '1', 669: '2', 670: '2', 671: '3', 672: '3', 673: '4', 9: '3', 10: '3', 17: '0', 1881: '1', 1882: '2', 1883: '2', 1884: '4'},
    'paid': {667: 'True', 668: 'True', 669: 'True', 670: 'True', 671: 'True', 672: 'True', 673: 'True', 9: 'False', 10: 'False', 17: 'True', 
            1881: 'True', 1882: 'True', 1883: 'True', 1884: 'True'},
    'service': {667: 'video', 668: 'audio', 669: 'video', 670: 'audio', 671: 'video', 672: 'audio', 673: 'audio', 9: 'video', 10: 'audio', 17: 'video',
            1881: 'audio', 1882: 'video', 1883: 'audio', 1884: 'audio'},
    'tier': {667: '2', 668: '1', 669: '2', 670: '2', 671: '1', 672: '1', 673: '1', 9: '1', 10: '1', 17: '2', 1881: '1', 1882: '2', 1883: '2', 1884: '1'},
    'promo': {667: 'intro', 668: 'intro', 669: 'intro', 670: 'intro', 671: 'intro', 672: 'intro', 673: 'intro', 9: 'base', 10: 'base', 17: 'base', 
            1881: 'base', 1882: 'base', 1883: 'base', 1884: 'base'},
    'price': {667: '11.99', 668: '5.99', 669: '11.99', 670: '9.99', 671: '8.99', 672: '5.99', 673: '5.99', 9: '10.99', 10: '8.99', 17: '15.99', 
            1881: '8.99', 1882: '15.99', 1883: '12.99', 1884: '8.99'},
    'eff_dt': {667: '2018-02-01', 668: '2018-02-01', 669: '2018-02-01', 670: '2018-02-01', 671: '2018-02-01', 672: '2018-02-01', 673: '2018-02-01',
            9: '2018-08-01', 10: '2018-08-01', 17: '2018-08-01', 1881: '2018-08-01', 1882: '2018-08-01', 1883: '2018-08-01', 1884: '2018-08-01'},
    'exp_dt': {667: '2018-07-31', 668: '2018-07-31', 669: '2018-07-31', 670: '2018-07-31', 671: '2018-07-31', 672: '2018-07-31', 673: '2018-07-31',
            9: '2018-08-31', 10: '2018-08-31', 17: '2019-02-28', 1881: '9999-12-31', 1882: '9999-12-31', 1883: '9999-12-31', 1884: '9999-12-31'}})
demo_audit_cols_ex3 = ['eff_dt', 'exp_dt']

print('df')
print(demo_df_ex3)
print()
print('audit_cols')
print(demo_audit_cols_ex3)
print()
print('existing_journal')
print(demo_existing_journal_ex3)
df
  id  paid service tier promo  price
0  1  True   audio    1  base   8.99
1  2  True   video    2  base  15.99
2  2  True   audio    2  base  12.99

audit_cols
['eff_dt', 'exp_dt']

existing_journal
     id   paid service tier  promo  price      eff_dt      exp_dt
667   0   True   video    2  intro  11.99  2018-02-01  2018-07-31
668   1   True   audio    1  intro   5.99  2018-02-01  2018-07-31
669   2   True   video    2  intro  11.99  2018-02-01  2018-07-31
670   2   True   audio    2  intro   9.99  2018-02-01  2018-07-31
671   3   True   video    1  intro   8.99  2018-02-01  2018-07-31
672   3   True   audio    1  intro   5.99  2018-02-01  2018-07-31
673   4   True   audio    1  intro   5.99  2018-02-01  2018-07-31
9     3  False   video    1   base  10.99  2018-08-01  2018-08-31
10    3  False   audio    1   base   8.99  2018-08-01  2018-08-31
17    0   True   video    2   base  15.99  2018-08-01  2019-02-28
1881  1   True   audio    1   base   8.99  2018-08-01  9999-12-31
1882  2   True   video    2   base  15.99  2018-08-01  9999-12-31
1883  2   True   audio    2   base  12.99  2018-08-01  9999-12-31
1884  4   True   audio    1   base   8.99  2018-08-01  9999-12-31

The demo included in the solution cell below should display the following output:

historical_journal WITH NO existing journal
Empty DataFrame
Columns: [id, paid, service, tier, promo, price, eff_dt, exp_dt]
Index: []

active_journal WITH NO existing journal
Empty DataFrame
Columns: [id, paid, service, tier, promo, price, eff_dt, exp_dt]
Index: []

historical_journal WITH existing journal
    id   paid service tier  promo  price      eff_dt      exp_dt
667  0   True   video    2  intro  11.99  2018-02-01  2018-07-31
668  1   True   audio    1  intro   5.99  2018-02-01  2018-07-31
669  2   True   video    2  intro  11.99  2018-02-01  2018-07-31
670  2   True   audio    2  intro   9.99  2018-02-01  2018-07-31
671  3   True   video    1  intro   8.99  2018-02-01  2018-07-31
672  3   True   audio    1  intro   5.99  2018-02-01  2018-07-31
673  4   True   audio    1  intro   5.99  2018-02-01  2018-07-31
9    3  False   video    1   base  10.99  2018-08-01  2018-08-31
10   3  False   audio    1   base   8.99  2018-08-01  2018-08-31
17   0   True   video    2   base  15.99  2018-08-01  2019-02-28

active_journal WITH existing journal
     id  paid service tier promo  price      eff_dt      exp_dt
1881  1  True   audio    1  base   8.99  2018-08-01  9999-12-31
1882  2  True   video    2  base  15.99  2018-08-01  9999-12-31
1883  2  True   audio    2  base  12.99  2018-08-01  9999-12-31
1884  4  True   audio    1  base   8.99  2018-08-01  9999-12-31

Note - This demo runs your solution two times. The first two DataFrames are the expected result when exixting_journal is None, and the second two DataFrames are the expected result for the existing_journal defined in the cell above.

In [40]:
### Exercise 3 solution
def partition_journal(df, audit_cols, existing_journal=None):
    ###
    ### YOUR CODE HERE
    ###
    
    # if existing_journal is None, create empty df with columns of df and audit_cols as its columns
    
    if existing_journal is None:
        df_cols = df.columns.tolist()
        df_cols.extend(audit_cols)
        existing_journal = pd.DataFrame(columns = df_cols)
    
    historical_journal = existing_journal[existing_journal['exp_dt'] != '9999-12-31']
    
    active_journal = existing_journal[existing_journal['exp_dt'] == '9999-12-31']
    
    return (historical_journal, active_journal)
   
    
### demo function call
new_hist, new_active = partition_journal(demo_df_ex3, demo_audit_cols_ex3)
hist, active = partition_journal(demo_df_ex3, demo_audit_cols_ex3, demo_existing_journal_ex3)
print('historical_journal WITH NO existing journal')
print(new_hist)
print()
print('active_journal WITH NO existing journal')
print(new_active)
print()
print('historical_journal WITH existing journal')
print(hist)
print()
print('active_journal WITH existing journal')
print(active)
historical_journal WITH NO existing journal
Empty DataFrame
Columns: [id, paid, service, tier, promo, price, eff_dt, exp_dt]
Index: []

active_journal WITH NO existing journal
Empty DataFrame
Columns: [id, paid, service, tier, promo, price, eff_dt, exp_dt]
Index: []

historical_journal WITH existing journal
    id   paid service tier  promo  price      eff_dt      exp_dt
667  0   True   video    2  intro  11.99  2018-02-01  2018-07-31
668  1   True   audio    1  intro   5.99  2018-02-01  2018-07-31
669  2   True   video    2  intro  11.99  2018-02-01  2018-07-31
670  2   True   audio    2  intro   9.99  2018-02-01  2018-07-31
671  3   True   video    1  intro   8.99  2018-02-01  2018-07-31
672  3   True   audio    1  intro   5.99  2018-02-01  2018-07-31
673  4   True   audio    1  intro   5.99  2018-02-01  2018-07-31
9    3  False   video    1   base  10.99  2018-08-01  2018-08-31
10   3  False   audio    1   base   8.99  2018-08-01  2018-08-31
17   0   True   video    2   base  15.99  2018-08-01  2019-02-28

active_journal WITH existing journal
     id  paid service tier promo  price      eff_dt      exp_dt
1881  1  True   audio    1  base   8.99  2018-08-01  9999-12-31
1882  2  True   video    2  base  15.99  2018-08-01  9999-12-31
1883  2  True   audio    2  base  12.99  2018-08-01  9999-12-31
1884  4  True   audio    1  base   8.99  2018-08-01  9999-12-31

The cell below will test your solution for Exercise 3. The testing variables will be available for debugging under the following names in a dictionary format.

  • input_vars - Input variables for your solution.
  • original_input_vars - Copy of input variables from prior to running your solution. These should be the same as input_vars - otherwise the inputs were modified by your solution.
  • returned_output_vars - Outputs returned by your solution.
  • true_output_vars - The expected output. This should "match" returned_output_vars based on the question requirements - otherwise, your solution is not returning the correct output.
In [41]:
### test_cell_ex3
exercise_start = time.time()
###
### AUTOGRADER TEST - DO NOT REMOVE
###
from tester_fw.testers import Tester

conf = {
    'case_file':'tc_3', 
    'func': partition_journal, # replace this with the function defined above
    'inputs':{ # input config dict. keys are parameter names
        'df':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'audit_cols':{
            'dtype':'list', # data type of param.
            'check_modified':True,
        },
        'existing_journal':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        }
    },
    'outputs':{
        'historical_journal':{
            'index':0,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': True, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        },
        'active_journal':{
            'index':1,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': True, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        }
        
    }
}
tester = Tester(conf, key=b'6IRWMcPsVIAZqzDJnPgv_MfUZsxqo4Utjm2Favidv-A=', path='resource/asnlib/publicdata/')
for _ in range(70):
    try:
        tester.run_test()
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
    except:
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
        raise

###
### AUTOGRADER TEST - DO NOT REMOVE
###
exercise_end = time.time()
print(f"This test executed in {(pd.to_datetime(exercise_end, unit='s') - pd.to_datetime(exercise_start, unit='s')).seconds} seconds")
print('Passed! Please submit.')
This test executed in 9 seconds
Passed! Please submit.

Helper function drop_rename_sort

Parameters

  • df - any pandas DataFrame
  • drop_pattern - regular expression pattern
  • rename_pattern - regular expression pattern
  • key_cols - list of strings (all of these strings must be column names of df)

Functionality

  • drop any columns in df which match drop_pattern
  • rename any of the remaining columns in df to names with the rename_pattern removed
  • sort the rows in the result by the key_cols in descending order
  • re-index the result
In [49]:
def drop_rename_sort(df, drop_pattern, rename_pattern, key_cols):
    import re
    return df\
        .drop(columns=[c for c in df.columns if re.search(drop_pattern, c) is not None])\
        .rename(columns={c: re.sub(rename_pattern, '', c) for c in df.columns})\
        .sort_values(key_cols)\
        .reset_index(drop=True)
In [50]:
df = pd.DataFrame([
    {'col_0': 'val_0_0', 'col_1_x':'val_1_0x', 'col_1_y':'val_1_0y', 'key_col_0':1, 'key_col_1':1},
    {'col_0': 'val_0_1', 'col_1_x':'val_1_1x', 'col_1_y':'val_1_1y', 'key_col_0':0, 'key_col_1':2},
    {'col_0': 'val_0_2', 'col_1_x':'val_1_2x', 'col_1_y':'val_1_2y', 'key_col_0':2, 'key_col_1':4},
    {'col_0': 'val_0_3', 'col_1_x':'val_1_3x', 'col_1_y':'val_1_3y', 'key_col_0':2, 'key_col_1':3}
])
print('df')
print(df)
drop_x = drop_rename_sort(df, '_x$', '_y$', ['key_col_0', 'key_col_1'])
print()
print("result - drop ")
print(drop_x)
df
     col_0   col_1_x   col_1_y  key_col_0  key_col_1
0  val_0_0  val_1_0x  val_1_0y          1          1
1  val_0_1  val_1_1x  val_1_1y          0          2
2  val_0_2  val_1_2x  val_1_2y          2          4
3  val_0_3  val_1_3x  val_1_3y          2          3

result - drop 
     col_0     col_1  key_col_0  key_col_1
0  val_0_1  val_1_1y          0          2
1  val_0_0  val_1_0y          1          1
2  val_0_3  val_1_3y          2          3
3  val_0_2  val_1_2y          2          4

Exercise 4 - (3 Points):

Motivation (don't dwell on this):
The next task is to determine which keys exist in both the active partition of the journal and the business data as well as which keys exist in only one or the other. Then we need to partition the business data into two parts (records with keys already in the journal and records without keys in the journal). We also need to partition the active journal data into two parts (records with keys existing in the business data and records without keys existing in the business data).

Requirements:
Define the function compare_to_journal(df, key_cols, active_journal).

The inputs are as follows:

  • df - a DataFrame.
  • active_journal - another DataFrame. It will have all of the columns which are in df, but it may have additional columns. This input may be an empty DataFrame having 0 records.
  • key_cols - a list of strings denoting some columns in df and active_journal. We can uniquely identify one record in either df or active_journal by a combination of these columns.

Your function should do the following:

  • "Outer merge" df and active_journal on the key_cols. Take a look at the indicator and suffixes parameters in the docs. Let's call the result merged.
  • Partition the rows in merged into these 3 partitions. The indicator parameter of merge will add an extra column to the result which is useful for this task. If you add it, it will need to be removed from the partitions.:
    • all rows in merged with keys existing only in df. Let's call this partition df_only.
    • all rows in merged with keys existing only in active_journal. Let's call this partition aj_only.
    • all rows in merged with keys existing in both df and active_journal. Let's call this partition both.
  • Make copies of slices taken from the partitions as follows. The suffixes parameter of merge adds suffixes to duplicate column names to indicate where each came from. The provided helper function drop_rename_sort can be used to perform the heavy lifting here. These DataFrames are what should be returned.
    • new_df - all columns from df_only which are not duplicate columns originating from active_journal.
    • expired_df - all columns from aj_only which are not duplicate columns originating from df.
    • compare_new_df - all columns from both which are not duplicate columns originating from active_journal.
    • compare_old_df - all columns from both which are not duplicate columns originating from df.

The newly created DataFrames should be returned as a tuple, i.e. return (new_df, expired_df, compare_new_df, compare_old_df).

All newly created DataFrames should be sorted lexographically based on key_cols.

Any suffixes or indicator columns added in the merge should not be included in the returned results. In other words, all 4 returned DataFrames should have the same column names as active_journal.

In [42]:
### Define demo inputs

demo_df_ex4 = pd.DataFrame([
    {'some_data_col':'some_new_value', 'some_key_col': 'new_key'},
    {'some_data_col':'some_changed_value', 'some_key_col': 'existing_key'},
    {'some_data_col':'other_changed_value', 'some_key_col': 'other_existing_key'}
])

demo_active_journal_ex4 = pd.DataFrame([
    {'some_data_col':'expiring_value', 'some_key_col': 'expiring_key', 'eff_dt': '0001-01-01', 'exp_dt':'9999-12-31'},
    {'some_data_col':'other_previous_value', 'some_key_col': 'other_existing_key', 'eff_dt': '0001-01-01', 'exp_dt':'9999-12-31'},
    {'some_data_col':'some_previous_value', 'some_key_col': 'existing_key', 'eff_dt': '6040-01-01', 'exp_dt':'9999-12-31'}
])

demo_key_cols_ex4 = ['some_key_col']

print('df')
print(demo_df_ex4)
print()
print('active_journal')
print(demo_active_journal_ex4)
print()
print('key_cols')
print(demo_key_cols_ex4)
df
         some_data_col        some_key_col
0       some_new_value             new_key
1   some_changed_value        existing_key
2  other_changed_value  other_existing_key

active_journal
          some_data_col        some_key_col      eff_dt      exp_dt
0        expiring_value        expiring_key  0001-01-01  9999-12-31
1  other_previous_value  other_existing_key  0001-01-01  9999-12-31
2   some_previous_value        existing_key  6040-01-01  9999-12-31

key_cols
['some_key_col']

The demo included in the solution cell below should display the following output:

new_df
    some_data_col some_key_col eff_dt exp_dt
0  some_new_value      new_key    NaN    NaN

expired_df
    some_data_col  some_key_col      eff_dt      exp_dt
0  expiring_value  expiring_key  0001-01-01  9999-12-31

compare_new_df
         some_data_col        some_key_col      eff_dt      exp_dt
0   some_changed_value        existing_key  6040-01-01  9999-12-31
1  other_changed_value  other_existing_key  0001-01-01  9999-12-31

compare_old_df
          some_data_col        some_key_col      eff_dt      exp_dt
0   some_previous_value        existing_key  6040-01-01  9999-12-31
1  other_previous_value  other_existing_key  0001-01-01  9999-12-31

Note: The key_cols and non-key columns may be something different than what are used in this demo. The demo names were chosen to make it clear which columns are keys and which columns are non-keys along with the effective date and expiration date.

The intermediate values from the demo should be the following if you set the indicator to add the extra column and suffixes to add '_df' and '_aj' suffixes to duplicate column names from df and active_journal respectively.

merged
      some_data_col_df        some_key_col      some_data_col_aj      eff_dt      exp_dt      _merge 
0       some_new_value             new_key                   NaN         NaN         NaN   left_only
1   some_changed_value        existing_key   some_previous_value  6040-01-01  9999-12-31        both
2  other_changed_value  other_existing_key  other_previous_value  0001-01-01  9999-12-31        both 
3                  NaN        expiring_key        expiring_value  0001-01-01  9999-12-31  right_only

df_only
  some_data_col_df some_key_col some_data_col_aj eff_dt exp_dt
0   some_new_value      new_key              NaN    NaN    NaN

aj_only
  some_data_col_df  some_key_col some_data_col_aj      eff_dt      exp_dt
3              NaN  expiring_key   expiring_value  0001-01-01  9999-12-31

both
      some_data_col_df        some_key_col      some_data_col_aj      eff_dt      exp_dt
1   some_changed_value        existing_key   some_previous_value  6040-01-01  9999-12-31
2  other_changed_value  other_existing_key  other_previous_value  0001-01-01  9999-12-31
In [55]:
### Exercise 4 solution
def compare_to_journal(df, key_cols, active_journal):
    ###
    ### YOUR CODE HERE
    ###
    
    # outer merge with df and active_journal on key_cols w/ indicator=True, suffixes=('_df' and '_aj')
    merged = df.merge(active_journal, how='outer', on=key_cols, indicator=True, suffixes=('_df', '_aj'))
    #display(merged)
    
    # df_only (all rows only in df)
    df_only = merged[merged['_merge'] == 'left_only']
    df_only = df_only.drop(columns=['_merge'])
    #display(df_only)
    
    # aj_only (all rows only in aj)
    aj_only = merged[merged['_merge'] == 'right_only']
    aj_only = aj_only.drop(columns=['_merge'])
    #display(aj_only)
    
    # both
    both = merged[merged['_merge'] == 'both']
    both = both.drop(columns=['_merge'])
    #display(both)
    
    #new_df --> df_only
    new_df = drop_rename_sort(df_only, '_aj$', '_df$', key_cols)
    #display(new_df)
    
    #expired_df --> aj_only
    expired_df = drop_rename_sort(aj_only, '_df$', '_aj$', key_cols)
    display(expired_df)
    
    #compare_new_df --> from both (drop _aj, rename _df)
    compare_new_df = drop_rename_sort(both, "_aj$", "_df$", key_cols)
    display(compare_new_df)
    
    #compare_old_df --> from both (drop _df, rename _aj)
    compare_old_df = drop_rename_sort(both, "_df$", "_aj$", key_cols)
    display(compare_old_df)
    
    
    return (new_df, expired_df, compare_new_df, compare_old_df)
    
### demo function call
demo_new_df, demo_expired_df, _demo_compare_new_df, demo_compare_old_df = compare_to_journal(demo_df_ex4, demo_key_cols_ex4, demo_active_journal_ex4)
print('new_df')
print(demo_new_df)
print()
print('expired_df')
print(demo_expired_df)
print()
print('compare_new_df')
print(_demo_compare_new_df)
print()
print('compare_old_df')
print(demo_compare_old_df)
some_key_col some_data_col eff_dt exp_dt
0 expiring_key expiring_value 0001-01-01 9999-12-31
some_data_col some_key_col eff_dt exp_dt
0 some_changed_value existing_key 6040-01-01 9999-12-31
1 other_changed_value other_existing_key 0001-01-01 9999-12-31
some_key_col some_data_col eff_dt exp_dt
0 existing_key some_previous_value 6040-01-01 9999-12-31
1 other_existing_key other_previous_value 0001-01-01 9999-12-31
new_df
    some_data_col some_key_col eff_dt exp_dt
0  some_new_value      new_key    NaN    NaN

expired_df
   some_key_col   some_data_col      eff_dt      exp_dt
0  expiring_key  expiring_value  0001-01-01  9999-12-31

compare_new_df
         some_data_col        some_key_col      eff_dt      exp_dt
0   some_changed_value        existing_key  6040-01-01  9999-12-31
1  other_changed_value  other_existing_key  0001-01-01  9999-12-31

compare_old_df
         some_key_col         some_data_col      eff_dt      exp_dt
0        existing_key   some_previous_value  6040-01-01  9999-12-31
1  other_existing_key  other_previous_value  0001-01-01  9999-12-31

The cell below will test your solution for Exercise 4. The testing variables will be available for debugging under the following names in a dictionary format.

  • input_vars - Input variables for your solution.
  • original_input_vars - Copy of input variables from prior to running your solution. These should be the same as input_vars - otherwise the inputs were modified by your solution.
  • returned_output_vars - Outputs returned by your solution.
  • true_output_vars - The expected output. This should "match" returned_output_vars based on the question requirements - otherwise, your solution is not returning the correct output.
In [56]:
### test_cell_ex4
exercise_start = time.time()
###
### AUTOGRADER TEST - DO NOT REMOVE
###
from tester_fw.testers import Tester

conf = {
    'case_file':'tc_4', 
    'func': compare_to_journal, # replace this with the function defined above
    'inputs':{ # input config dict. keys are parameter names
        'df':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'key_cols':{
            'dtype':'list', # data type of param.
            'check_modified':True,
        },
        'active_journal':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        }
    },
    'outputs':{
        'new_df':{
            'index':0,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': True, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        },
        'expired_df':{
            'index':1,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': True, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        },
        'compare_new_df':{
            'index':2,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': True, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        },
        'compare_old_df':{
            'index':3,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': True, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        }
    }
}
tester = Tester(conf, key=b'6IRWMcPsVIAZqzDJnPgv_MfUZsxqo4Utjm2Favidv-A=', path='resource/asnlib/publicdata/')
for _ in range(70):
    try:
        tester.run_test()
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
    except:
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
        raise

###
### AUTOGRADER TEST - DO NOT REMOVE
###
exercise_end = time.time()
print(f"This test executed in {(pd.to_datetime(exercise_end, unit='s') - pd.to_datetime(exercise_start, unit='s')).seconds} seconds")
print('Passed! Please submit.')
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 156 audio True 2 base 12.99 2018-11-01 9999-12-31
1 162 audio True 1 base 8.99 2018-12-01 9999-12-31
2 162 video True 1 base 10.99 2018-12-01 9999-12-31
3 215 video True 1 base 10.99 2019-01-01 9999-12-31
4 435 video True 1 base 10.99 2019-04-01 9999-12-31
5 444 video False 2 base 15.99 2019-04-01 9999-12-31
6 784 audio True 1 intro 5.99 2019-04-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 1 True audio 2 base 12.99 2018-08-01 9999-12-31
3 1 True video 2 base 15.99 2018-08-01 9999-12-31
4 10 True audio 2 base 12.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
1011 96 True video 2 base 15.99 2018-10-01 9999-12-31
1012 97 True video 2 base 15.99 2018-10-01 9999-12-31
1013 98 True audio 1 base 8.99 2018-10-01 9999-12-31
1014 99 True audio 2 base 12.99 2018-10-01 9999-12-31
1015 99 True video 2 base 15.99 2018-10-01 9999-12-31

1016 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 1 audio True 2 base 12.99 2018-08-01 9999-12-31
3 1 video True 2 base 15.99 2018-08-01 9999-12-31
4 10 audio True 2 base 12.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
1011 96 video True 2 base 15.99 2018-10-01 9999-12-31
1012 97 video True 2 base 15.99 2018-10-01 9999-12-31
1013 98 audio True 1 base 8.99 2018-10-01 9999-12-31
1014 99 audio True 1 base 8.99 2018-10-01 9999-12-31
1015 99 video True 1 base 10.99 2018-10-01 9999-12-31

1016 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 1015 audio True 2 intro 9.99 2019-11-01 9999-12-31
1 193 audio True 1 base 8.99 2018-12-01 9999-12-31
2 193 video True 1 base 10.99 2018-12-01 9999-12-31
3 225 audio True 2 base 12.99 2019-01-01 9999-12-31
4 297 audio True 2 base 12.99 2019-02-01 9999-12-31
5 36 audio True 2 base 12.99 2018-08-01 9999-12-31
6 36 video True 2 base 15.99 2018-08-01 9999-12-31
7 38 audio False 1 base 8.99 2019-12-01 9999-12-31
8 38 video False 1 base 10.99 2019-12-01 9999-12-31
9 40 video True 2 base 15.99 2018-09-01 9999-12-31
10 416 audio True 1 base 8.99 2019-05-01 9999-12-31
11 416 video True 1 base 10.99 2019-05-01 9999-12-31
12 428 audio True 2 base 12.99 2019-05-01 9999-12-31
13 428 video True 2 base 15.99 2019-05-01 9999-12-31
14 543 audio True 1 base 8.99 2019-07-01 9999-12-31
15 620 video True 2 base 15.99 2019-09-01 9999-12-31
16 682 audio False 1 base 8.99 2019-12-01 9999-12-31
17 682 video False 1 base 10.99 2019-12-01 9999-12-31
18 690 video True 1 base 10.99 2019-10-01 9999-12-31
19 782 audio True 2 base 12.99 2019-12-01 9999-12-31
20 847 video False 1 intro 8.99 2019-12-01 9999-12-31
21 878 video True 2 intro 11.99 2019-08-01 9999-12-31
22 931 video True 1 intro 8.99 2019-10-01 9999-12-31
23 965 audio False 1 intro 5.99 2019-12-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 2 base 12.99 2018-08-01 9999-12-31
1 10 True audio 2 base 12.99 2018-12-01 9999-12-31
2 10 True video 2 base 15.99 2018-12-01 9999-12-31
3 100 True video 1 base 10.99 2018-10-01 9999-12-31
4 1000 True video 1 intro 8.99 2019-11-01 9999-12-31
... ... ... ... ... ... ... ... ...
1224 995 True audio 2 intro 9.99 2019-11-01 9999-12-31
1225 996 True audio 1 intro 5.99 2019-11-01 9999-12-31
1226 997 True video 1 intro 8.99 2019-11-01 9999-12-31
1227 998 True video 1 intro 8.99 2019-11-01 9999-12-31
1228 999 True video 1 intro 8.99 2019-11-01 9999-12-31

1229 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 2 base 12.99 2018-08-01 9999-12-31
1 10 audio True 2 base 12.99 2018-12-01 9999-12-31
2 10 video True 2 base 15.99 2018-12-01 9999-12-31
3 100 video True 1 base 10.99 2018-10-01 9999-12-31
4 1000 video True 1 intro 8.99 2019-11-01 9999-12-31
... ... ... ... ... ... ... ... ...
1224 995 audio True 2 intro 9.99 2019-11-01 9999-12-31
1225 996 audio True 1 intro 5.99 2019-11-01 9999-12-31
1226 997 video True 1 intro 8.99 2019-11-01 9999-12-31
1227 998 video True 1 intro 8.99 2019-11-01 9999-12-31
1228 999 video True 1 intro 8.99 2019-11-01 9999-12-31

1229 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 159 video True 1 intro 8.99 2018-06-01 9999-12-31
1 189 video False 1 intro 8.99 2018-10-01 9999-12-31
2 202 audio True 2 intro 9.99 2018-07-01 9999-12-31
3 202 video True 2 intro 11.99 2018-07-01 9999-12-31
4 210 audio True 1 intro 5.99 2018-07-01 9999-12-31
5 211 audio True 1 intro 5.99 2018-07-01 9999-12-31
6 243 audio True 1 intro 5.99 2018-07-01 9999-12-31
7 243 video True 1 intro 8.99 2018-07-01 9999-12-31
8 250 audio True 1 intro 5.99 2018-07-01 9999-12-31
9 273 audio True 2 intro 9.99 2018-08-01 9999-12-31
10 342 audio True 1 intro 5.99 2018-09-01 9999-12-31
11 342 video True 1 intro 8.99 2018-09-01 9999-12-31
12 48 audio True 1 base 8.99 2018-09-01 9999-12-31
13 66 video True 1 base 10.99 2018-09-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 1 True audio 2 base 12.99 2018-08-01 9999-12-31
3 10 True audio 2 base 12.99 2018-08-01 9999-12-31
4 100 True video 1 base 10.99 2018-05-01 9999-12-31
... ... ... ... ... ... ... ... ...
484 97 True video 1 base 10.99 2018-05-01 9999-12-31
485 98 True audio 1 base 8.99 2018-05-01 9999-12-31
486 98 True video 1 base 10.99 2018-05-01 9999-12-31
487 99 True audio 1 base 8.99 2018-05-01 9999-12-31
488 99 True video 1 base 10.99 2018-05-01 9999-12-31

489 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 1 audio True 2 base 12.99 2018-08-01 9999-12-31
3 10 audio True 2 base 12.99 2018-08-01 9999-12-31
4 100 video True 1 intro 8.99 2018-05-01 9999-12-31
... ... ... ... ... ... ... ... ...
484 97 video True 1 intro 8.99 2018-05-01 9999-12-31
485 98 audio True 1 intro 5.99 2018-05-01 9999-12-31
486 98 video True 1 intro 8.99 2018-05-01 9999-12-31
487 99 audio True 1 intro 5.99 2018-05-01 9999-12-31
488 99 video True 1 intro 8.99 2018-05-01 9999-12-31

489 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 101 audio True 1 intro 5.99 2018-04-01 9999-12-31
1 107 audio False 1 intro 5.99 2018-06-01 9999-12-31
2 107 video False 1 intro 8.99 2018-06-01 9999-12-31
3 113 audio True 2 intro 9.99 2018-04-01 9999-12-31
4 156 audio True 2 intro 9.99 2018-05-01 9999-12-31
5 156 video True 2 intro 11.99 2018-05-01 9999-12-31
6 67 audio True 1 intro 5.99 2018-03-01 9999-12-31
7 67 video True 1 intro 8.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True video 1 intro 8.99 2018-02-01 9999-12-31
1 1 True audio 2 intro 9.99 2018-02-01 9999-12-31
2 10 True audio 2 intro 9.99 2018-02-01 9999-12-31
3 103 True video 2 intro 11.99 2018-04-01 9999-12-31
4 104 True audio 2 intro 9.99 2018-06-01 9999-12-31
... ... ... ... ... ... ... ... ...
306 97 True video 1 intro 8.99 2018-04-01 9999-12-31
307 98 True audio 2 intro 9.99 2018-04-01 9999-12-31
308 98 True video 2 intro 11.99 2018-04-01 9999-12-31
309 99 True audio 1 intro 5.99 2018-04-01 9999-12-31
310 99 True video 1 intro 8.99 2018-04-01 9999-12-31

311 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 video True 1 intro 8.99 2018-02-01 9999-12-31
1 1 audio True 2 intro 9.99 2018-02-01 9999-12-31
2 10 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 103 video True 2 intro 11.99 2018-04-01 9999-12-31
4 104 audio False 2 intro 9.99 2018-06-01 9999-12-31
... ... ... ... ... ... ... ... ...
306 97 video True 1 intro 8.99 2018-04-01 9999-12-31
307 98 audio True 2 intro 9.99 2018-04-01 9999-12-31
308 98 video True 2 intro 11.99 2018-04-01 9999-12-31
309 99 audio True 1 intro 5.99 2018-04-01 9999-12-31
310 99 video True 1 intro 8.99 2018-04-01 9999-12-31

311 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 100 audio False 2 base 12.99 2019-02-01 9999-12-31
1 120 audio True 2 base 12.99 2018-10-01 9999-12-31
2 128 audio True 2 base 12.99 2018-10-01 9999-12-31
3 128 video True 2 base 15.99 2018-10-01 9999-12-31
4 131 audio True 1 base 8.99 2018-10-01 9999-12-31
5 19 audio True 1 base 8.99 2018-08-01 9999-12-31
6 209 audio True 2 base 12.99 2018-12-01 9999-12-31
7 209 video True 2 base 15.99 2018-12-01 9999-12-31
8 218 audio True 1 base 8.99 2018-12-01 9999-12-31
9 218 video True 1 base 10.99 2018-12-01 9999-12-31
10 223 audio True 1 base 8.99 2018-12-01 9999-12-31
11 223 video True 1 base 10.99 2018-12-01 9999-12-31
12 326 audio False 1 base 8.99 2019-02-01 9999-12-31
13 326 video False 1 base 10.99 2019-02-01 9999-12-31
14 374 video True 2 intro 11.99 2018-09-01 9999-12-31
15 427 audio True 2 intro 9.99 2018-10-01 9999-12-31
16 569 video False 2 intro 11.99 2019-02-01 9999-12-31
17 67 audio True 1 base 8.99 2018-09-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 1 True audio 1 base 8.99 2018-08-01 9999-12-31
1 10 True audio 1 base 8.99 2018-08-01 9999-12-31
2 101 True audio 2 base 12.99 2018-10-01 9999-12-31
3 101 True video 2 base 15.99 2018-10-01 9999-12-31
4 102 True audio 1 base 8.99 2018-10-01 9999-12-31
... ... ... ... ... ... ... ... ...
846 95 True video 1 base 10.99 2018-10-01 9999-12-31
847 96 True audio 1 base 8.99 2018-10-01 9999-12-31
848 97 True video 1 base 10.99 2018-10-01 9999-12-31
849 98 True video 1 base 10.99 2018-10-01 9999-12-31
850 99 True audio 1 base 8.99 2018-10-01 9999-12-31

851 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 1 audio True 1 base 8.99 2018-08-01 9999-12-31
1 10 audio True 1 base 8.99 2018-08-01 9999-12-31
2 101 audio True 2 base 12.99 2018-10-01 9999-12-31
3 101 video True 2 base 15.99 2018-10-01 9999-12-31
4 102 audio True 1 base 8.99 2018-10-01 9999-12-31
... ... ... ... ... ... ... ... ...
846 95 video True 1 base 10.99 2018-10-01 9999-12-31
847 96 audio True 1 base 8.99 2018-10-01 9999-12-31
848 97 video True 1 base 10.99 2018-10-01 9999-12-31
849 98 video True 1 base 10.99 2018-10-01 9999-12-31
850 99 audio True 1 base 8.99 2018-10-01 9999-12-31

851 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 12 audio False 1 intro 5.99 2018-03-01 9999-12-31
1 12 video False 1 intro 8.99 2018-03-01 9999-12-31
2 3 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 3 video True 2 intro 11.99 2018-02-01 9999-12-31
4 58 video True 1 intro 8.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 1 True audio 2 intro 9.99 2018-02-01 9999-12-31
2 10 True audio 2 intro 9.99 2018-02-01 9999-12-31
3 10 True video 2 intro 11.99 2018-02-01 9999-12-31
4 11 True audio 1 intro 5.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
133 93 True video 1 intro 8.99 2018-03-01 9999-12-31
134 94 True video 1 intro 8.99 2018-03-01 9999-12-31
135 95 True audio 2 intro 9.99 2018-03-01 9999-12-31
136 96 True audio 1 intro 5.99 2018-03-01 9999-12-31
137 96 True video 1 intro 8.99 2018-03-01 9999-12-31

138 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 1 audio True 2 intro 9.99 2018-02-01 9999-12-31
2 10 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 10 video True 2 intro 11.99 2018-02-01 9999-12-31
4 11 audio True 1 intro 5.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
133 93 video True 1 intro 8.99 2018-03-01 9999-12-31
134 94 video True 1 intro 8.99 2018-03-01 9999-12-31
135 95 audio True 2 intro 9.99 2018-03-01 9999-12-31
136 96 audio True 1 intro 5.99 2018-03-01 9999-12-31
137 96 video True 1 intro 8.99 2018-03-01 9999-12-31

138 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 130 audio True 1 intro 5.99 2018-04-01 9999-12-31
1 168 video True 2 intro 11.99 2018-05-01 9999-12-31
2 227 audio True 2 intro 9.99 2018-06-01 9999-12-31
3 227 video True 2 intro 11.99 2018-06-01 9999-12-31
4 244 video False 1 intro 8.99 2018-07-01 9999-12-31
5 88 audio True 1 intro 5.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-02-01 9999-12-31
1 1 True video 2 base 15.99 2018-02-01 9999-12-31
2 10 True video 1 base 10.99 2018-02-01 9999-12-31
3 100 True audio 1 intro 5.99 2018-04-01 9999-12-31
4 101 True video 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
352 95 True video 1 intro 8.99 2018-03-01 9999-12-31
353 96 True audio 1 intro 5.99 2018-04-01 9999-12-31
354 97 True video 2 intro 11.99 2018-04-01 9999-12-31
355 98 True audio 1 intro 5.99 2018-04-01 9999-12-31
356 99 True video 2 intro 11.99 2018-04-01 9999-12-31

357 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 1 video True 2 intro 11.99 2018-02-01 9999-12-31
2 10 video True 1 intro 8.99 2018-02-01 9999-12-31
3 100 audio True 1 intro 5.99 2018-04-01 9999-12-31
4 101 video True 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
352 95 video True 1 intro 8.99 2018-03-01 9999-12-31
353 96 audio True 1 intro 5.99 2018-04-01 9999-12-31
354 97 video True 2 intro 11.99 2018-04-01 9999-12-31
355 98 audio True 1 intro 5.99 2018-04-01 9999-12-31
356 99 video True 2 intro 11.99 2018-04-01 9999-12-31

357 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 1015 audio True 2 intro 9.99 2019-11-01 9999-12-31
1 193 audio True 1 base 8.99 2018-12-01 9999-12-31
2 193 video True 1 base 10.99 2018-12-01 9999-12-31
3 225 audio True 2 base 12.99 2019-01-01 9999-12-31
4 297 audio True 2 base 12.99 2019-02-01 9999-12-31
5 36 audio True 2 base 12.99 2018-08-01 9999-12-31
6 36 video True 2 base 15.99 2018-08-01 9999-12-31
7 38 audio False 1 base 8.99 2019-12-01 9999-12-31
8 38 video False 1 base 10.99 2019-12-01 9999-12-31
9 40 video True 2 base 15.99 2018-09-01 9999-12-31
10 416 audio True 1 base 8.99 2019-05-01 9999-12-31
11 416 video True 1 base 10.99 2019-05-01 9999-12-31
12 428 audio True 2 base 12.99 2019-05-01 9999-12-31
13 428 video True 2 base 15.99 2019-05-01 9999-12-31
14 543 audio True 1 base 8.99 2019-07-01 9999-12-31
15 620 video True 2 base 15.99 2019-09-01 9999-12-31
16 682 audio False 1 base 8.99 2019-12-01 9999-12-31
17 682 video False 1 base 10.99 2019-12-01 9999-12-31
18 690 video True 1 base 10.99 2019-10-01 9999-12-31
19 782 audio True 2 base 12.99 2019-12-01 9999-12-31
20 847 video False 1 intro 8.99 2019-12-01 9999-12-31
21 878 video True 2 intro 11.99 2019-08-01 9999-12-31
22 931 video True 1 intro 8.99 2019-10-01 9999-12-31
23 965 audio False 1 intro 5.99 2019-12-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 2 base 12.99 2018-08-01 9999-12-31
1 10 True audio 2 base 12.99 2018-12-01 9999-12-31
2 10 True video 2 base 15.99 2018-12-01 9999-12-31
3 100 True video 1 base 10.99 2018-10-01 9999-12-31
4 1000 True video 1 intro 8.99 2019-11-01 9999-12-31
... ... ... ... ... ... ... ... ...
1224 995 True audio 2 intro 9.99 2019-11-01 9999-12-31
1225 996 True audio 1 intro 5.99 2019-11-01 9999-12-31
1226 997 True video 1 intro 8.99 2019-11-01 9999-12-31
1227 998 True video 1 intro 8.99 2019-11-01 9999-12-31
1228 999 True video 1 intro 8.99 2019-11-01 9999-12-31

1229 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 2 base 12.99 2018-08-01 9999-12-31
1 10 audio True 2 base 12.99 2018-12-01 9999-12-31
2 10 video True 2 base 15.99 2018-12-01 9999-12-31
3 100 video True 1 base 10.99 2018-10-01 9999-12-31
4 1000 video True 1 intro 8.99 2019-11-01 9999-12-31
... ... ... ... ... ... ... ... ...
1224 995 audio True 2 intro 9.99 2019-11-01 9999-12-31
1225 996 audio True 1 intro 5.99 2019-11-01 9999-12-31
1226 997 video True 1 intro 8.99 2019-11-01 9999-12-31
1227 998 video True 1 intro 8.99 2019-11-01 9999-12-31
1228 999 video True 1 intro 8.99 2019-11-01 9999-12-31

1229 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 12 audio False 1 intro 5.99 2018-03-01 9999-12-31
1 12 video False 1 intro 8.99 2018-03-01 9999-12-31
2 3 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 3 video True 2 intro 11.99 2018-02-01 9999-12-31
4 58 video True 1 intro 8.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 1 True audio 2 intro 9.99 2018-02-01 9999-12-31
2 10 True audio 2 intro 9.99 2018-02-01 9999-12-31
3 10 True video 2 intro 11.99 2018-02-01 9999-12-31
4 11 True audio 1 intro 5.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
133 93 True video 1 intro 8.99 2018-03-01 9999-12-31
134 94 True video 1 intro 8.99 2018-03-01 9999-12-31
135 95 True audio 2 intro 9.99 2018-03-01 9999-12-31
136 96 True audio 1 intro 5.99 2018-03-01 9999-12-31
137 96 True video 1 intro 8.99 2018-03-01 9999-12-31

138 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 1 audio True 2 intro 9.99 2018-02-01 9999-12-31
2 10 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 10 video True 2 intro 11.99 2018-02-01 9999-12-31
4 11 audio True 1 intro 5.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
133 93 video True 1 intro 8.99 2018-03-01 9999-12-31
134 94 video True 1 intro 8.99 2018-03-01 9999-12-31
135 95 audio True 2 intro 9.99 2018-03-01 9999-12-31
136 96 audio True 1 intro 5.99 2018-03-01 9999-12-31
137 96 video True 1 intro 8.99 2018-03-01 9999-12-31

138 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 178 audio True 2 base 12.99 2018-12-01 9999-12-31
1 186 audio False 2 base 12.99 2019-01-01 9999-12-31
2 256 audio True 2 base 12.99 2019-01-01 9999-12-31
3 256 video True 2 base 15.99 2019-01-01 9999-12-31
4 447 audio True 2 intro 9.99 2018-10-01 9999-12-31
5 505 audio False 1 intro 5.99 2019-01-01 9999-12-31
6 560 video False 1 intro 8.99 2019-01-01 9999-12-31
7 61 audio False 2 base 12.99 2019-01-01 9999-12-31
8 68 audio True 2 base 12.99 2018-09-01 9999-12-31
9 68 video True 2 base 15.99 2018-09-01 9999-12-31
10 82 audio True 2 base 12.99 2019-01-01 9999-12-31
11 82 video True 2 base 15.99 2019-01-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 1 True audio 2 base 12.99 2018-08-01 9999-12-31
3 1 True video 2 base 15.99 2018-08-01 9999-12-31
4 10 True audio 2 base 12.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
879 96 True video 2 base 15.99 2018-10-01 9999-12-31
880 97 True video 2 base 15.99 2018-10-01 9999-12-31
881 98 True audio 1 base 8.99 2018-10-01 9999-12-31
882 99 True audio 1 base 8.99 2018-10-01 9999-12-31
883 99 True video 1 base 10.99 2018-10-01 9999-12-31

884 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 1 audio True 2 base 12.99 2018-08-01 9999-12-31
3 1 video True 2 base 15.99 2018-08-01 9999-12-31
4 10 audio True 2 base 12.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
879 96 video True 2 base 15.99 2018-10-01 9999-12-31
880 97 video True 2 base 15.99 2018-10-01 9999-12-31
881 98 audio True 1 base 8.99 2018-10-01 9999-12-31
882 99 audio True 1 base 8.99 2018-10-01 9999-12-31
883 99 video True 1 base 10.99 2018-10-01 9999-12-31

884 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 0 True video 1 intro 8.99 2018-02-01 9999-12-31
2 1 True audio 2 intro 9.99 2018-02-01 9999-12-31
3 10 True audio 1 intro 5.99 2018-02-01 9999-12-31
4 11 True audio 2 intro 9.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
98 76 True audio 1 intro 5.99 2018-03-01 9999-12-31
99 76 True video 1 intro 8.99 2018-03-01 9999-12-31
100 8 True video 2 intro 11.99 2018-02-01 9999-12-31
101 9 True audio 1 intro 5.99 2018-02-01 9999-12-31
102 9 True video 1 intro 8.99 2018-02-01 9999-12-31

103 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 0 video True 1 intro 8.99 2018-02-01 9999-12-31
2 1 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 10 audio True 1 intro 5.99 2018-02-01 9999-12-31
4 11 audio True 2 intro 9.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
98 76 audio True 1 intro 5.99 2018-03-01 9999-12-31
99 76 video True 1 intro 8.99 2018-03-01 9999-12-31
100 8 video True 2 intro 11.99 2018-02-01 9999-12-31
101 9 audio True 1 intro 5.99 2018-02-01 9999-12-31
102 9 video True 1 intro 8.99 2018-02-01 9999-12-31

103 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 1 True video 1 intro 8.99 2018-02-01 9999-12-31
2 10 True audio 2 intro 9.99 2018-02-01 9999-12-31
3 10 True video 2 intro 11.99 2018-02-01 9999-12-31
4 11 True video 2 intro 11.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
70 6 True audio 2 intro 9.99 2018-02-01 9999-12-31
71 6 True video 2 intro 11.99 2018-02-01 9999-12-31
72 7 True video 1 intro 8.99 2018-02-01 9999-12-31
73 8 True video 1 intro 8.99 2018-02-01 9999-12-31
74 9 True audio 2 intro 9.99 2018-02-01 9999-12-31

75 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 1 video True 1 intro 8.99 2018-02-01 9999-12-31
2 10 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 10 video True 2 intro 11.99 2018-02-01 9999-12-31
4 11 video True 2 intro 11.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
70 6 audio True 2 intro 9.99 2018-02-01 9999-12-31
71 6 video True 2 intro 11.99 2018-02-01 9999-12-31
72 7 video True 1 intro 8.99 2018-02-01 9999-12-31
73 8 video True 1 intro 8.99 2018-02-01 9999-12-31
74 9 audio True 2 intro 9.99 2018-02-01 9999-12-31

75 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 20 audio True 1 base 8.99 2018-08-01 9999-12-31
1 309 audio True 1 intro 5.99 2018-07-01 9999-12-31
2 343 audio True 2 intro 9.99 2018-08-01 9999-12-31
3 343 video True 2 intro 11.99 2018-08-01 9999-12-31
4 472 audio True 2 intro 9.99 2018-10-01 9999-12-31
5 472 video True 2 intro 11.99 2018-10-01 9999-12-31
6 64 audio True 1 base 8.99 2018-09-01 9999-12-31
7 91 video True 1 base 10.99 2018-09-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 10 True video 2 base 15.99 2018-08-01 9999-12-31
3 100 True audio 2 base 12.99 2018-09-01 9999-12-31
4 101 True audio 2 base 12.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
642 95 True video 1 base 10.99 2018-09-01 9999-12-31
643 96 True audio 2 base 12.99 2018-09-01 9999-12-31
644 97 True audio 2 base 12.99 2018-09-01 9999-12-31
645 98 True video 1 base 10.99 2018-09-01 9999-12-31
646 99 True audio 1 base 8.99 2018-09-01 9999-12-31

647 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 10 video True 2 base 15.99 2018-08-01 9999-12-31
3 100 audio True 2 base 12.99 2018-09-01 9999-12-31
4 101 audio True 2 base 12.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
642 95 video True 1 base 10.99 2018-09-01 9999-12-31
643 96 audio True 2 base 12.99 2018-09-01 9999-12-31
644 97 audio True 2 base 12.99 2018-09-01 9999-12-31
645 98 video True 1 base 10.99 2018-09-01 9999-12-31
646 99 audio True 1 base 8.99 2018-09-01 9999-12-31

647 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 109 video True 1 base 10.99 2018-09-01 9999-12-31
1 180 audio True 2 base 12.99 2018-11-01 9999-12-31
2 180 video True 2 base 15.99 2018-11-01 9999-12-31
3 292 audio False 1 base 8.99 2019-09-01 9999-12-31
4 387 audio True 2 base 12.99 2019-05-01 9999-12-31
5 446 audio True 1 base 8.99 2019-05-01 9999-12-31
6 446 video True 1 base 10.99 2019-05-01 9999-12-31
7 454 audio True 1 base 8.99 2019-05-01 9999-12-31
8 456 audio True 1 base 8.99 2019-05-01 9999-12-31
9 565 audio True 1 base 8.99 2019-07-01 9999-12-31
10 565 video True 1 base 10.99 2019-07-01 9999-12-31
11 573 audio False 1 base 8.99 2019-09-01 9999-12-31
12 643 audio True 1 base 8.99 2019-08-01 9999-12-31
13 643 video True 1 base 10.99 2019-08-01 9999-12-31
14 656 audio True 1 base 8.99 2019-08-01 9999-12-31
15 656 video True 1 base 10.99 2019-08-01 9999-12-31
16 695 audio False 1 base 8.99 2019-09-01 9999-12-31
17 695 video False 1 base 10.99 2019-09-01 9999-12-31
18 803 audio False 1 intro 5.99 2019-09-01 9999-12-31
19 963 audio True 2 intro 9.99 2019-08-01 9999-12-31
20 963 video True 2 intro 11.99 2019-08-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 10 True audio 1 base 8.99 2018-08-01 9999-12-31
1 100 True audio 1 base 8.99 2018-09-01 9999-12-31
2 100 True video 1 base 10.99 2018-09-01 9999-12-31
3 1000 True audio 1 intro 5.99 2019-09-01 9999-12-31
4 1001 True audio 1 intro 5.99 2019-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
1195 996 True audio 1 intro 5.99 2019-09-01 9999-12-31
1196 997 True audio 1 intro 5.99 2019-09-01 9999-12-31
1197 997 True video 1 intro 8.99 2019-09-01 9999-12-31
1198 998 True audio 1 intro 5.99 2019-09-01 9999-12-31
1199 999 True video 1 intro 8.99 2019-09-01 9999-12-31

1200 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 10 audio True 1 base 8.99 2018-08-01 9999-12-31
1 100 audio True 1 base 8.99 2018-09-01 9999-12-31
2 100 video True 1 base 10.99 2018-09-01 9999-12-31
3 1000 audio True 1 intro 5.99 2019-09-01 9999-12-31
4 1001 audio True 1 intro 5.99 2019-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
1195 996 audio True 1 intro 5.99 2019-09-01 9999-12-31
1196 997 audio True 1 intro 5.99 2019-09-01 9999-12-31
1197 997 video True 1 intro 8.99 2019-09-01 9999-12-31
1198 998 audio True 1 intro 5.99 2019-09-01 9999-12-31
1199 999 video True 1 intro 8.99 2019-09-01 9999-12-31

1200 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 19 audio True 1 base 8.99 2018-08-01 9999-12-31
1 212 audio True 1 base 8.99 2018-11-01 9999-12-31
2 212 video True 1 base 10.99 2018-11-01 9999-12-31
3 240 audio True 1 base 8.99 2018-12-01 9999-12-31
4 240 video True 1 base 10.99 2018-12-01 9999-12-31
5 264 audio True 1 base 8.99 2018-12-01 9999-12-31
6 264 video True 1 base 10.99 2018-12-01 9999-12-31
7 276 audio True 1 base 8.99 2019-01-01 9999-12-31
8 316 audio True 1 base 8.99 2019-02-01 9999-12-31
9 316 video True 1 base 10.99 2019-02-01 9999-12-31
10 321 video True 1 base 10.99 2019-02-01 9999-12-31
11 440 audio True 2 intro 9.99 2018-10-01 9999-12-31
12 440 video True 2 intro 11.99 2018-10-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 2 base 12.99 2018-08-01 9999-12-31
1 0 True video 2 base 15.99 2018-08-01 9999-12-31
2 1 True video 1 base 10.99 2018-08-01 9999-12-31
3 100 True audio 1 base 8.99 2018-09-01 9999-12-31
4 101 True audio 1 base 8.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
868 96 True video 2 base 15.99 2018-09-01 9999-12-31
869 97 True audio 1 base 8.99 2018-09-01 9999-12-31
870 97 True video 1 base 10.99 2018-09-01 9999-12-31
871 99 True audio 1 base 8.99 2018-09-01 9999-12-31
872 99 True video 1 base 10.99 2018-09-01 9999-12-31

873 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 2 base 12.99 2018-08-01 9999-12-31
1 0 video True 2 base 15.99 2018-08-01 9999-12-31
2 1 video True 1 base 10.99 2018-08-01 9999-12-31
3 100 audio True 1 base 8.99 2018-09-01 9999-12-31
4 101 audio True 1 base 8.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
868 96 video True 2 base 15.99 2018-09-01 9999-12-31
869 97 audio True 1 base 8.99 2018-09-01 9999-12-31
870 97 video True 1 base 10.99 2018-09-01 9999-12-31
871 99 audio True 1 base 8.99 2018-09-01 9999-12-31
872 99 video True 1 base 10.99 2018-09-01 9999-12-31

873 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 1034 video True 1 intro 8.99 2019-09-01 9999-12-31
1 1042 audio True 2 intro 9.99 2019-10-01 9999-12-31
2 1042 video True 2 intro 11.99 2019-10-01 9999-12-31
3 131 video True 2 base 15.99 2018-10-01 9999-12-31
4 234 audio True 2 base 12.99 2018-11-01 9999-12-31
5 234 video True 2 base 15.99 2018-11-01 9999-12-31
6 295 audio True 2 base 12.99 2019-04-01 9999-12-31
7 311 audio False 1 base 8.99 2019-11-01 9999-12-31
8 311 video False 1 base 10.99 2019-11-01 9999-12-31
9 360 audio True 1 base 8.99 2019-03-01 9999-12-31
10 360 video True 1 base 10.99 2019-03-01 9999-12-31
11 464 video True 1 base 10.99 2019-04-01 9999-12-31
12 624 audio True 1 base 8.99 2019-07-01 9999-12-31
13 624 video True 1 base 10.99 2019-07-01 9999-12-31
14 658 audio True 1 base 8.99 2019-08-01 9999-12-31
15 658 video True 1 base 10.99 2019-08-01 9999-12-31
16 705 video False 2 base 15.99 2019-11-01 9999-12-31
17 784 audio False 1 base 8.99 2019-11-01 9999-12-31
18 915 audio True 1 intro 5.99 2019-08-01 9999-12-31
19 915 video True 1 intro 8.99 2019-08-01 9999-12-31
20 926 audio False 2 intro 9.99 2019-11-01 9999-12-31
21 926 video False 2 intro 11.99 2019-11-01 9999-12-31
22 955 audio True 2 intro 9.99 2019-08-01 9999-12-31
23 961 audio False 1 intro 5.99 2019-11-01 9999-12-31
24 961 video False 1 intro 8.99 2019-11-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 2 base 12.99 2018-08-01 9999-12-31
1 0 True video 2 base 15.99 2018-08-01 9999-12-31
2 1 True video 1 base 10.99 2018-08-01 9999-12-31
3 100 True audio 1 base 8.99 2018-09-01 9999-12-31
4 1000 True video 1 intro 8.99 2019-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
1296 995 True video 1 intro 8.99 2019-09-01 9999-12-31
1297 996 True audio 1 intro 5.99 2019-09-01 9999-12-31
1298 997 True audio 1 intro 5.99 2019-09-01 9999-12-31
1299 998 True audio 2 intro 9.99 2019-09-01 9999-12-31
1300 999 True audio 1 intro 5.99 2019-09-01 9999-12-31

1301 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 2 base 12.99 2018-08-01 9999-12-31
1 0 video True 2 base 15.99 2018-08-01 9999-12-31
2 1 video True 1 base 10.99 2018-08-01 9999-12-31
3 100 audio True 1 base 8.99 2018-09-01 9999-12-31
4 1000 video True 1 intro 8.99 2019-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
1296 995 video True 1 intro 8.99 2019-09-01 9999-12-31
1297 996 audio True 1 intro 5.99 2019-09-01 9999-12-31
1298 997 audio True 1 intro 5.99 2019-09-01 9999-12-31
1299 998 audio True 2 intro 9.99 2019-09-01 9999-12-31
1300 999 audio True 1 intro 5.99 2019-09-01 9999-12-31

1301 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 0 True video 1 intro 8.99 2018-02-01 9999-12-31
2 1 True audio 2 intro 9.99 2018-02-01 9999-12-31
3 10 True audio 1 intro 5.99 2018-02-01 9999-12-31
4 11 True audio 2 intro 9.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
98 76 True audio 1 intro 5.99 2018-03-01 9999-12-31
99 76 True video 1 intro 8.99 2018-03-01 9999-12-31
100 8 True video 2 intro 11.99 2018-02-01 9999-12-31
101 9 True audio 1 intro 5.99 2018-02-01 9999-12-31
102 9 True video 1 intro 8.99 2018-02-01 9999-12-31

103 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 0 video True 1 intro 8.99 2018-02-01 9999-12-31
2 1 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 10 audio True 1 intro 5.99 2018-02-01 9999-12-31
4 11 audio True 2 intro 9.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
98 76 audio True 1 intro 5.99 2018-03-01 9999-12-31
99 76 video True 1 intro 8.99 2018-03-01 9999-12-31
100 8 video True 2 intro 11.99 2018-02-01 9999-12-31
101 9 audio True 1 intro 5.99 2018-02-01 9999-12-31
102 9 video True 1 intro 8.99 2018-02-01 9999-12-31

103 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 105 audio True 2 intro 9.99 2018-04-01 9999-12-31
1 129 audio True 1 intro 5.99 2018-05-01 9999-12-31
2 129 video True 1 intro 8.99 2018-05-01 9999-12-31
3 141 audio True 1 intro 5.99 2018-05-01 9999-12-31
4 141 video True 1 intro 8.99 2018-05-01 9999-12-31
5 155 audio True 1 intro 5.99 2018-05-01 9999-12-31
6 186 audio True 2 intro 9.99 2018-06-01 9999-12-31
7 186 video True 2 intro 11.99 2018-06-01 9999-12-31
8 19 audio True 1 intro 5.99 2018-02-01 9999-12-31
9 245 audio False 2 intro 9.99 2018-07-01 9999-12-31
10 245 video False 2 intro 11.99 2018-07-01 9999-12-31
11 256 audio True 2 intro 9.99 2018-07-01 9999-12-31
12 256 video True 2 intro 11.99 2018-07-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 1 True audio 2 base 12.99 2018-02-01 9999-12-31
1 1 True video 2 base 15.99 2018-02-01 9999-12-31
2 10 True audio 2 base 12.99 2018-02-01 9999-12-31
3 100 True audio 2 intro 9.99 2018-04-01 9999-12-31
4 100 True video 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
374 96 True video 1 intro 8.99 2018-04-01 9999-12-31
375 97 True audio 1 intro 5.99 2018-04-01 9999-12-31
376 97 True video 1 intro 8.99 2018-04-01 9999-12-31
377 98 True video 1 intro 8.99 2018-04-01 9999-12-31
378 99 True audio 1 intro 5.99 2018-04-01 9999-12-31

379 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 1 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 1 video True 1 intro 8.99 2018-02-01 9999-12-31
2 10 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 100 audio True 2 intro 9.99 2018-04-01 9999-12-31
4 100 video True 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
374 96 video True 1 intro 8.99 2018-04-01 9999-12-31
375 97 audio True 1 intro 5.99 2018-04-01 9999-12-31
376 97 video True 1 intro 8.99 2018-04-01 9999-12-31
377 98 video True 1 intro 8.99 2018-04-01 9999-12-31
378 99 audio True 1 intro 5.99 2018-04-01 9999-12-31

379 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 145 audio False 1 base 8.99 2019-03-01 9999-12-31
1 145 video False 1 base 10.99 2019-03-01 9999-12-31
2 250 video True 1 base 10.99 2018-12-01 9999-12-31
3 253 audio False 1 base 8.99 2019-03-01 9999-12-31
4 253 video False 1 base 10.99 2019-03-01 9999-12-31
5 293 video True 1 base 10.99 2019-01-01 9999-12-31
6 510 audio True 1 intro 5.99 2018-11-01 9999-12-31
7 510 video True 1 intro 8.99 2018-11-01 9999-12-31
8 538 audio False 1 intro 5.99 2019-03-01 9999-12-31
9 593 audio True 1 intro 5.99 2018-12-01 9999-12-31
10 613 audio True 1 intro 5.99 2019-01-01 9999-12-31
11 613 video True 1 intro 8.99 2019-01-01 9999-12-31
12 630 audio True 1 intro 5.99 2019-01-01 9999-12-31
13 668 audio True 1 intro 5.99 2019-02-01 9999-12-31
14 709 video True 1 intro 8.99 2019-03-01 9999-12-31
15 91 video True 1 base 10.99 2018-09-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 1 True audio 1 base 8.99 2018-08-01 9999-12-31
3 1 True video 1 base 10.99 2018-08-01 9999-12-31
4 10 True video 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
867 96 True video 1 base 10.99 2018-09-01 9999-12-31
868 97 True audio 2 base 12.99 2018-09-01 9999-12-31
869 97 True video 2 base 15.99 2018-09-01 9999-12-31
870 99 True audio 2 base 12.99 2018-09-01 9999-12-31
871 99 True video 2 base 15.99 2018-09-01 9999-12-31

872 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 1 audio True 1 base 8.99 2018-08-01 9999-12-31
3 1 video True 1 base 10.99 2018-08-01 9999-12-31
4 10 video True 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
867 96 video True 1 base 10.99 2018-09-01 9999-12-31
868 97 audio True 2 base 12.99 2018-09-01 9999-12-31
869 97 video True 2 base 15.99 2018-09-01 9999-12-31
870 99 audio True 2 base 12.99 2018-09-01 9999-12-31
871 99 video True 2 base 15.99 2018-09-01 9999-12-31

872 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 174 audio True 1 intro 5.99 2018-05-01 9999-12-31
1 174 video True 1 intro 8.99 2018-05-01 9999-12-31
2 231 audio True 1 intro 5.99 2018-06-01 9999-12-31
3 289 audio True 1 intro 5.99 2018-07-01 9999-12-31
4 34 audio True 2 intro 9.99 2018-02-01 9999-12-31
5 67 video True 2 intro 11.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-02-01 9999-12-31
1 0 True video 1 base 10.99 2018-02-01 9999-12-31
2 1 True audio 1 base 8.99 2018-02-01 9999-12-31
3 1 True video 1 base 10.99 2018-02-01 9999-12-31
4 10 True video 1 base 10.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
379 97 True audio 2 intro 9.99 2018-03-01 9999-12-31
380 97 True video 2 intro 11.99 2018-03-01 9999-12-31
381 98 True audio 1 intro 5.99 2018-03-01 9999-12-31
382 99 True audio 2 intro 9.99 2018-03-01 9999-12-31
383 99 True video 2 intro 11.99 2018-03-01 9999-12-31

384 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 0 video True 1 intro 8.99 2018-02-01 9999-12-31
2 1 audio True 1 intro 5.99 2018-02-01 9999-12-31
3 1 video True 1 intro 8.99 2018-02-01 9999-12-31
4 10 video True 1 intro 8.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
379 97 audio True 2 intro 9.99 2018-03-01 9999-12-31
380 97 video True 2 intro 11.99 2018-03-01 9999-12-31
381 98 audio True 1 intro 5.99 2018-03-01 9999-12-31
382 99 audio True 2 intro 9.99 2018-03-01 9999-12-31
383 99 video True 2 intro 11.99 2018-03-01 9999-12-31

384 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 109 video True 1 base 10.99 2018-09-01 9999-12-31
1 180 audio True 2 base 12.99 2018-11-01 9999-12-31
2 180 video True 2 base 15.99 2018-11-01 9999-12-31
3 292 audio False 1 base 8.99 2019-09-01 9999-12-31
4 387 audio True 2 base 12.99 2019-05-01 9999-12-31
5 446 audio True 1 base 8.99 2019-05-01 9999-12-31
6 446 video True 1 base 10.99 2019-05-01 9999-12-31
7 454 audio True 1 base 8.99 2019-05-01 9999-12-31
8 456 audio True 1 base 8.99 2019-05-01 9999-12-31
9 565 audio True 1 base 8.99 2019-07-01 9999-12-31
10 565 video True 1 base 10.99 2019-07-01 9999-12-31
11 573 audio False 1 base 8.99 2019-09-01 9999-12-31
12 643 audio True 1 base 8.99 2019-08-01 9999-12-31
13 643 video True 1 base 10.99 2019-08-01 9999-12-31
14 656 audio True 1 base 8.99 2019-08-01 9999-12-31
15 656 video True 1 base 10.99 2019-08-01 9999-12-31
16 695 audio False 1 base 8.99 2019-09-01 9999-12-31
17 695 video False 1 base 10.99 2019-09-01 9999-12-31
18 803 audio False 1 intro 5.99 2019-09-01 9999-12-31
19 963 audio True 2 intro 9.99 2019-08-01 9999-12-31
20 963 video True 2 intro 11.99 2019-08-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 10 True audio 1 base 8.99 2018-08-01 9999-12-31
1 100 True audio 1 base 8.99 2018-09-01 9999-12-31
2 100 True video 1 base 10.99 2018-09-01 9999-12-31
3 1000 True audio 1 intro 5.99 2019-09-01 9999-12-31
4 1001 True audio 1 intro 5.99 2019-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
1195 996 True audio 1 intro 5.99 2019-09-01 9999-12-31
1196 997 True audio 1 intro 5.99 2019-09-01 9999-12-31
1197 997 True video 1 intro 8.99 2019-09-01 9999-12-31
1198 998 True audio 1 intro 5.99 2019-09-01 9999-12-31
1199 999 True video 1 intro 8.99 2019-09-01 9999-12-31

1200 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 10 audio True 1 base 8.99 2018-08-01 9999-12-31
1 100 audio True 1 base 8.99 2018-09-01 9999-12-31
2 100 video True 1 base 10.99 2018-09-01 9999-12-31
3 1000 audio True 1 intro 5.99 2019-09-01 9999-12-31
4 1001 audio True 1 intro 5.99 2019-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
1195 996 audio True 1 intro 5.99 2019-09-01 9999-12-31
1196 997 audio True 1 intro 5.99 2019-09-01 9999-12-31
1197 997 video True 1 intro 8.99 2019-09-01 9999-12-31
1198 998 audio True 1 intro 5.99 2019-09-01 9999-12-31
1199 999 video True 1 intro 8.99 2019-09-01 9999-12-31

1200 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 0 True video 1 intro 8.99 2018-02-01 9999-12-31
2 1 True audio 2 intro 9.99 2018-02-01 9999-12-31
3 10 True audio 1 intro 5.99 2018-02-01 9999-12-31
4 11 True audio 2 intro 9.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
98 76 True audio 1 intro 5.99 2018-03-01 9999-12-31
99 76 True video 1 intro 8.99 2018-03-01 9999-12-31
100 8 True video 2 intro 11.99 2018-02-01 9999-12-31
101 9 True audio 1 intro 5.99 2018-02-01 9999-12-31
102 9 True video 1 intro 8.99 2018-02-01 9999-12-31

103 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 0 video True 1 intro 8.99 2018-02-01 9999-12-31
2 1 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 10 audio True 1 intro 5.99 2018-02-01 9999-12-31
4 11 audio True 2 intro 9.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
98 76 audio True 1 intro 5.99 2018-03-01 9999-12-31
99 76 video True 1 intro 8.99 2018-03-01 9999-12-31
100 8 video True 2 intro 11.99 2018-02-01 9999-12-31
101 9 audio True 1 intro 5.99 2018-02-01 9999-12-31
102 9 video True 1 intro 8.99 2018-02-01 9999-12-31

103 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 160 audio True 1 base 8.99 2019-12-01 9999-12-31
1 275 video True 1 base 10.99 2019-02-01 9999-12-31
2 461 video True 1 base 10.99 2019-05-01 9999-12-31
3 507 video True 1 base 10.99 2019-06-01 9999-12-31
4 571 audio True 1 base 8.99 2019-08-01 9999-12-31
5 659 video True 1 base 10.99 2019-10-01 9999-12-31
6 682 audio True 1 base 8.99 2019-11-01 9999-12-31
7 715 audio True 2 base 12.99 2019-12-01 9999-12-31
8 715 video True 2 base 15.99 2019-12-01 9999-12-31
9 771 video True 2 intro 11.99 2019-09-01 9999-12-31
10 799 audio True 1 intro 5.99 2019-08-01 9999-12-31
11 896 audio True 2 intro 9.99 2019-10-01 9999-12-31
12 933 audio False 2 intro 9.99 2019-12-01 9999-12-31
13 938 video True 2 intro 11.99 2019-10-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True video 1 base 10.99 2019-10-01 9999-12-31
1 1 True video 1 base 10.99 2019-09-01 9999-12-31
2 100 True audio 2 base 12.99 2019-07-01 9999-12-31
3 1000 True audio 1 intro 5.99 2019-12-01 9999-12-31
4 1001 True audio 2 intro 9.99 2019-12-01 9999-12-31
... ... ... ... ... ... ... ... ...
1145 997 True video 2 intro 11.99 2019-12-01 9999-12-31
1146 998 True audio 2 intro 9.99 2019-12-01 9999-12-31
1147 998 True video 2 intro 11.99 2019-12-01 9999-12-31
1148 999 True audio 1 intro 5.99 2019-12-01 9999-12-31
1149 999 True video 1 intro 8.99 2019-12-01 9999-12-31

1150 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 video True 1 base 10.99 2019-10-01 9999-12-31
1 1 video True 1 base 10.99 2019-09-01 9999-12-31
2 100 audio True 2 base 12.99 2019-07-01 9999-12-31
3 1000 audio True 1 intro 5.99 2019-12-01 9999-12-31
4 1001 audio True 2 intro 9.99 2019-12-01 9999-12-31
... ... ... ... ... ... ... ... ...
1145 997 video True 2 intro 11.99 2019-12-01 9999-12-31
1146 998 audio True 2 intro 9.99 2019-12-01 9999-12-31
1147 998 video True 2 intro 11.99 2019-12-01 9999-12-31
1148 999 audio True 1 intro 5.99 2019-12-01 9999-12-31
1149 999 video True 1 intro 8.99 2019-12-01 9999-12-31

1150 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 158 video True 2 base 15.99 2018-11-01 9999-12-31
1 163 audio True 2 base 12.99 2018-11-01 9999-12-31
2 163 video True 2 base 15.99 2018-11-01 9999-12-31
3 240 audio True 1 base 8.99 2018-12-01 9999-12-31
4 240 video True 1 base 10.99 2018-12-01 9999-12-31
5 254 audio True 1 base 8.99 2018-12-01 9999-12-31
6 260 audio True 1 base 8.99 2018-12-01 9999-12-31
7 260 video True 1 base 10.99 2018-12-01 9999-12-31
8 280 audio True 2 base 12.99 2019-01-01 9999-12-31
9 338 video True 2 base 15.99 2019-03-01 9999-12-31
10 403 audio True 1 base 8.99 2019-04-01 9999-12-31
11 403 video True 1 base 10.99 2019-04-01 9999-12-31
12 496 audio True 1 intro 5.99 2018-12-01 9999-12-31
13 496 video True 1 intro 8.99 2018-12-01 9999-12-31
14 58 audio True 1 base 8.99 2019-04-01 9999-12-31
15 58 video True 1 base 10.99 2019-04-01 9999-12-31
16 610 video False 1 intro 8.99 2019-04-01 9999-12-31
17 87 audio True 1 base 8.99 2018-09-01 9999-12-31
18 87 video True 1 base 10.99 2018-09-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 10 True audio 1 base 8.99 2018-08-01 9999-12-31
1 100 True audio 1 base 8.99 2018-09-01 9999-12-31
2 100 True video 1 base 10.99 2018-09-01 9999-12-31
3 101 True audio 1 base 8.99 2018-09-01 9999-12-31
4 102 True audio 1 base 8.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
936 95 True video 1 base 10.99 2018-09-01 9999-12-31
937 96 True audio 2 base 12.99 2018-09-01 9999-12-31
938 97 True video 1 base 10.99 2018-09-01 9999-12-31
939 98 True video 2 base 15.99 2018-09-01 9999-12-31
940 99 True video 1 base 10.99 2018-09-01 9999-12-31

941 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 10 audio True 1 base 8.99 2018-08-01 9999-12-31
1 100 audio True 1 base 8.99 2018-09-01 9999-12-31
2 100 video True 1 base 10.99 2018-09-01 9999-12-31
3 101 audio True 1 base 8.99 2018-09-01 9999-12-31
4 102 audio True 1 base 8.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
936 95 video True 1 base 10.99 2018-09-01 9999-12-31
937 96 audio True 2 base 12.99 2018-09-01 9999-12-31
938 97 video True 1 base 10.99 2018-09-01 9999-12-31
939 98 video True 2 base 15.99 2018-09-01 9999-12-31
940 99 video True 1 base 10.99 2018-09-01 9999-12-31

941 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 151 audio True 1 intro 5.99 2018-04-01 9999-12-31
1 151 video True 1 intro 8.99 2018-04-01 9999-12-31
2 270 audio False 1 intro 5.99 2018-08-01 9999-12-31
3 275 audio False 1 intro 5.99 2018-08-01 9999-12-31
4 55 audio False 2 intro 9.99 2018-08-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 1 True video 2 base 15.99 2018-08-01 9999-12-31
2 10 True video 1 base 10.99 2018-08-01 9999-12-31
3 100 True audio 1 intro 5.99 2018-04-01 9999-12-31
4 101 True video 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
382 95 True video 1 base 10.99 2018-03-01 9999-12-31
383 96 True audio 1 intro 5.99 2018-04-01 9999-12-31
384 97 True video 2 intro 11.99 2018-04-01 9999-12-31
385 98 True audio 1 intro 5.99 2018-04-01 9999-12-31
386 99 True video 2 intro 11.99 2018-04-01 9999-12-31

387 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 1 video True 2 base 15.99 2018-08-01 9999-12-31
2 10 video True 1 base 10.99 2018-08-01 9999-12-31
3 100 audio True 1 intro 5.99 2018-04-01 9999-12-31
4 101 video True 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
382 95 video True 1 intro 8.99 2018-03-01 9999-12-31
383 96 audio True 1 intro 5.99 2018-04-01 9999-12-31
384 97 video True 2 intro 11.99 2018-04-01 9999-12-31
385 98 audio True 1 intro 5.99 2018-04-01 9999-12-31
386 99 video True 2 intro 11.99 2018-04-01 9999-12-31

387 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 138 video True 1 base 10.99 2018-10-01 9999-12-31
1 150 audio True 1 base 8.99 2018-11-01 9999-12-31
2 150 video True 1 base 10.99 2018-11-01 9999-12-31
3 388 video True 2 intro 11.99 2018-09-01 9999-12-31
4 420 video False 1 intro 8.99 2018-11-01 9999-12-31
5 89 audio False 1 base 8.99 2018-11-01 9999-12-31
6 89 video False 1 base 10.99 2018-11-01 9999-12-31
7 91 audio False 1 base 8.99 2018-11-01 9999-12-31
8 91 video False 1 base 10.99 2018-11-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 10 True audio 1 base 8.99 2018-08-01 9999-12-31
3 100 True audio 1 base 8.99 2018-09-01 9999-12-31
4 100 True video 1 base 10.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
578 95 True video 1 base 10.99 2018-09-01 9999-12-31
579 96 True audio 2 base 12.99 2018-09-01 9999-12-31
580 97 True video 1 base 10.99 2018-09-01 9999-12-31
581 98 True video 2 base 15.99 2018-09-01 9999-12-31
582 99 True video 1 base 10.99 2018-09-01 9999-12-31

583 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 10 audio True 1 base 8.99 2018-08-01 9999-12-31
3 100 audio True 1 base 8.99 2018-09-01 9999-12-31
4 100 video True 1 base 10.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
578 95 video True 1 base 10.99 2018-09-01 9999-12-31
579 96 audio True 2 base 12.99 2018-09-01 9999-12-31
580 97 video True 1 base 10.99 2018-09-01 9999-12-31
581 98 video True 2 base 15.99 2018-09-01 9999-12-31
582 99 video True 1 base 10.99 2018-09-01 9999-12-31

583 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 42 audio True 2 intro 9.99 2018-04-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True video 1 intro 8.99 2018-02-01 9999-12-31
1 1 True audio 1 intro 5.99 2018-02-01 9999-12-31
2 10 True video 1 intro 8.99 2018-02-01 9999-12-31
3 11 True audio 2 intro 9.99 2018-02-01 9999-12-31
4 11 True video 2 intro 11.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
97 72 True audio 1 intro 5.99 2018-04-01 9999-12-31
98 72 True video 1 intro 8.99 2018-04-01 9999-12-31
99 8 True audio 2 intro 9.99 2018-02-01 9999-12-31
100 8 True video 2 intro 11.99 2018-02-01 9999-12-31
101 9 True audio 2 intro 9.99 2018-02-01 9999-12-31

102 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 video True 1 intro 8.99 2018-02-01 9999-12-31
1 1 audio True 1 intro 5.99 2018-02-01 9999-12-31
2 10 video True 1 intro 8.99 2018-02-01 9999-12-31
3 11 audio True 2 intro 9.99 2018-02-01 9999-12-31
4 11 video True 2 intro 11.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
97 72 audio True 1 intro 5.99 2018-04-01 9999-12-31
98 72 video True 1 intro 8.99 2018-04-01 9999-12-31
99 8 audio True 2 intro 9.99 2018-02-01 9999-12-31
100 8 video True 2 intro 11.99 2018-02-01 9999-12-31
101 9 audio True 2 intro 9.99 2018-02-01 9999-12-31

102 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 151 audio True 1 intro 5.99 2018-04-01 9999-12-31
1 151 video True 1 intro 8.99 2018-04-01 9999-12-31
2 270 audio False 1 intro 5.99 2018-08-01 9999-12-31
3 275 audio False 1 intro 5.99 2018-08-01 9999-12-31
4 55 audio False 2 intro 9.99 2018-08-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 1 True video 2 base 15.99 2018-08-01 9999-12-31
2 10 True video 1 base 10.99 2018-08-01 9999-12-31
3 100 True audio 1 intro 5.99 2018-04-01 9999-12-31
4 101 True video 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
382 95 True video 1 base 10.99 2018-03-01 9999-12-31
383 96 True audio 1 intro 5.99 2018-04-01 9999-12-31
384 97 True video 2 intro 11.99 2018-04-01 9999-12-31
385 98 True audio 1 intro 5.99 2018-04-01 9999-12-31
386 99 True video 2 intro 11.99 2018-04-01 9999-12-31

387 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 1 video True 2 base 15.99 2018-08-01 9999-12-31
2 10 video True 1 base 10.99 2018-08-01 9999-12-31
3 100 audio True 1 intro 5.99 2018-04-01 9999-12-31
4 101 video True 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
382 95 video True 1 intro 8.99 2018-03-01 9999-12-31
383 96 audio True 1 intro 5.99 2018-04-01 9999-12-31
384 97 video True 2 intro 11.99 2018-04-01 9999-12-31
385 98 audio True 1 intro 5.99 2018-04-01 9999-12-31
386 99 video True 2 intro 11.99 2018-04-01 9999-12-31

387 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 138 video True 1 base 10.99 2018-10-01 9999-12-31
1 150 audio True 1 base 8.99 2018-11-01 9999-12-31
2 150 video True 1 base 10.99 2018-11-01 9999-12-31
3 388 video True 2 intro 11.99 2018-09-01 9999-12-31
4 420 video False 1 intro 8.99 2018-11-01 9999-12-31
5 89 audio False 1 base 8.99 2018-11-01 9999-12-31
6 89 video False 1 base 10.99 2018-11-01 9999-12-31
7 91 audio False 1 base 8.99 2018-11-01 9999-12-31
8 91 video False 1 base 10.99 2018-11-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 10 True audio 1 base 8.99 2018-08-01 9999-12-31
3 100 True audio 1 base 8.99 2018-09-01 9999-12-31
4 100 True video 1 base 10.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
578 95 True video 1 base 10.99 2018-09-01 9999-12-31
579 96 True audio 2 base 12.99 2018-09-01 9999-12-31
580 97 True video 1 base 10.99 2018-09-01 9999-12-31
581 98 True video 2 base 15.99 2018-09-01 9999-12-31
582 99 True video 1 base 10.99 2018-09-01 9999-12-31

583 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 10 audio True 1 base 8.99 2018-08-01 9999-12-31
3 100 audio True 1 base 8.99 2018-09-01 9999-12-31
4 100 video True 1 base 10.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
578 95 video True 1 base 10.99 2018-09-01 9999-12-31
579 96 audio True 2 base 12.99 2018-09-01 9999-12-31
580 97 video True 1 base 10.99 2018-09-01 9999-12-31
581 98 video True 2 base 15.99 2018-09-01 9999-12-31
582 99 video True 1 base 10.99 2018-09-01 9999-12-31

583 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 1 True audio 1 intro 5.99 2018-02-01 9999-12-31
2 1 True video 1 intro 8.99 2018-02-01 9999-12-31
3 10 True audio 2 intro 9.99 2018-02-01 9999-12-31
4 12 True audio 2 intro 9.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
87 69 True audio 1 intro 5.99 2018-03-01 9999-12-31
88 7 True audio 1 intro 5.99 2018-02-01 9999-12-31
89 8 True audio 1 intro 5.99 2018-02-01 9999-12-31
90 8 True video 1 intro 8.99 2018-02-01 9999-12-31
91 9 True audio 2 intro 9.99 2018-02-01 9999-12-31

92 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 1 audio True 1 intro 5.99 2018-02-01 9999-12-31
2 1 video True 1 intro 8.99 2018-02-01 9999-12-31
3 10 audio True 2 intro 9.99 2018-02-01 9999-12-31
4 12 audio True 2 intro 9.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
87 69 audio True 1 intro 5.99 2018-03-01 9999-12-31
88 7 audio True 1 intro 5.99 2018-02-01 9999-12-31
89 8 audio True 1 intro 5.99 2018-02-01 9999-12-31
90 8 video True 1 intro 8.99 2018-02-01 9999-12-31
91 9 audio True 2 intro 9.99 2018-02-01 9999-12-31

92 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 1015 audio True 2 intro 9.99 2019-11-01 9999-12-31
1 193 audio True 1 base 8.99 2018-12-01 9999-12-31
2 193 video True 1 base 10.99 2018-12-01 9999-12-31
3 225 audio True 2 base 12.99 2019-01-01 9999-12-31
4 297 audio True 2 base 12.99 2019-02-01 9999-12-31
5 36 audio True 2 base 12.99 2018-08-01 9999-12-31
6 36 video True 2 base 15.99 2018-08-01 9999-12-31
7 38 audio False 1 base 8.99 2019-12-01 9999-12-31
8 38 video False 1 base 10.99 2019-12-01 9999-12-31
9 40 video True 2 base 15.99 2018-09-01 9999-12-31
10 416 audio True 1 base 8.99 2019-05-01 9999-12-31
11 416 video True 1 base 10.99 2019-05-01 9999-12-31
12 428 audio True 2 base 12.99 2019-05-01 9999-12-31
13 428 video True 2 base 15.99 2019-05-01 9999-12-31
14 543 audio True 1 base 8.99 2019-07-01 9999-12-31
15 620 video True 2 base 15.99 2019-09-01 9999-12-31
16 682 audio False 1 base 8.99 2019-12-01 9999-12-31
17 682 video False 1 base 10.99 2019-12-01 9999-12-31
18 690 video True 1 base 10.99 2019-10-01 9999-12-31
19 782 audio True 2 base 12.99 2019-12-01 9999-12-31
20 847 video False 1 intro 8.99 2019-12-01 9999-12-31
21 878 video True 2 intro 11.99 2019-08-01 9999-12-31
22 931 video True 1 intro 8.99 2019-10-01 9999-12-31
23 965 audio False 1 intro 5.99 2019-12-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 2 base 12.99 2018-08-01 9999-12-31
1 10 True audio 2 base 12.99 2018-12-01 9999-12-31
2 10 True video 2 base 15.99 2018-12-01 9999-12-31
3 100 True video 1 base 10.99 2018-10-01 9999-12-31
4 1000 True video 1 intro 8.99 2019-11-01 9999-12-31
... ... ... ... ... ... ... ... ...
1224 995 True audio 2 intro 9.99 2019-11-01 9999-12-31
1225 996 True audio 1 intro 5.99 2019-11-01 9999-12-31
1226 997 True video 1 intro 8.99 2019-11-01 9999-12-31
1227 998 True video 1 intro 8.99 2019-11-01 9999-12-31
1228 999 True video 1 intro 8.99 2019-11-01 9999-12-31

1229 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 2 base 12.99 2018-08-01 9999-12-31
1 10 audio True 2 base 12.99 2018-12-01 9999-12-31
2 10 video True 2 base 15.99 2018-12-01 9999-12-31
3 100 video True 1 base 10.99 2018-10-01 9999-12-31
4 1000 video True 1 intro 8.99 2019-11-01 9999-12-31
... ... ... ... ... ... ... ... ...
1224 995 audio True 2 intro 9.99 2019-11-01 9999-12-31
1225 996 audio True 1 intro 5.99 2019-11-01 9999-12-31
1226 997 video True 1 intro 8.99 2019-11-01 9999-12-31
1227 998 video True 1 intro 8.99 2019-11-01 9999-12-31
1228 999 video True 1 intro 8.99 2019-11-01 9999-12-31

1229 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 102 audio True 1 base 8.99 2018-11-01 9999-12-31
1 115 audio True 2 base 12.99 2018-12-01 9999-12-31
2 14 video True 1 base 10.99 2019-04-01 9999-12-31
3 171 audio True 2 base 12.99 2019-01-01 9999-12-31
4 344 audio True 1 base 8.99 2019-05-01 9999-12-31
5 381 audio False 1 base 8.99 2019-05-01 9999-12-31
6 388 audio False 1 intro 5.99 2019-05-01 9999-12-31
7 388 video False 1 intro 8.99 2019-05-01 9999-12-31
8 398 audio True 1 intro 5.99 2018-12-01 9999-12-31
9 475 audio False 1 intro 5.99 2019-05-01 9999-12-31
10 475 video False 1 intro 8.99 2019-05-01 9999-12-31
11 589 video False 1 intro 8.99 2019-05-01 9999-12-31
12 620 video True 1 intro 8.99 2019-05-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True video 1 base 10.99 2018-08-01 9999-12-31
1 1 True audio 1 base 8.99 2018-08-01 9999-12-31
2 10 True video 1 base 10.99 2018-08-01 9999-12-31
3 101 True audio 2 base 12.99 2018-11-01 9999-12-31
4 103 True audio 1 base 8.99 2018-11-01 9999-12-31
... ... ... ... ... ... ... ... ...
806 94 True audio 2 base 12.99 2018-11-01 9999-12-31
807 95 True video 1 base 10.99 2018-11-01 9999-12-31
808 96 True audio 1 base 8.99 2018-11-01 9999-12-31
809 98 True audio 1 base 8.99 2018-11-01 9999-12-31
810 98 True video 1 base 10.99 2018-11-01 9999-12-31

811 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 video True 1 base 10.99 2018-08-01 9999-12-31
1 1 audio True 1 base 8.99 2018-08-01 9999-12-31
2 10 video True 1 base 10.99 2018-08-01 9999-12-31
3 101 audio True 2 base 12.99 2018-11-01 9999-12-31
4 103 audio True 1 base 8.99 2018-11-01 9999-12-31
... ... ... ... ... ... ... ... ...
806 94 audio True 2 base 12.99 2018-11-01 9999-12-31
807 95 video True 1 base 10.99 2018-11-01 9999-12-31
808 96 audio True 1 base 8.99 2018-11-01 9999-12-31
809 98 audio True 1 base 8.99 2018-11-01 9999-12-31
810 98 video True 1 base 10.99 2018-11-01 9999-12-31

811 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 28 video False 2 intro 11.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 0 True video 1 intro 8.99 2018-02-01 9999-12-31
2 1 True audio 1 intro 5.99 2018-02-01 9999-12-31
3 10 True audio 2 intro 9.99 2018-02-01 9999-12-31
4 100 True audio 1 intro 5.99 2018-03-01 9999-12-31
... ... ... ... ... ... ... ... ...
146 97 True audio 1 intro 5.99 2018-03-01 9999-12-31
147 97 True video 1 intro 8.99 2018-03-01 9999-12-31
148 98 True audio 1 intro 5.99 2018-03-01 9999-12-31
149 99 True audio 2 intro 9.99 2018-03-01 9999-12-31
150 99 True video 2 intro 11.99 2018-03-01 9999-12-31

151 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 0 video True 1 intro 8.99 2018-02-01 9999-12-31
2 1 audio True 1 intro 5.99 2018-02-01 9999-12-31
3 10 audio True 2 intro 9.99 2018-02-01 9999-12-31
4 100 audio True 1 intro 5.99 2018-03-01 9999-12-31
... ... ... ... ... ... ... ... ...
146 97 audio True 1 intro 5.99 2018-03-01 9999-12-31
147 97 video True 1 intro 8.99 2018-03-01 9999-12-31
148 98 audio True 1 intro 5.99 2018-03-01 9999-12-31
149 99 audio True 2 intro 9.99 2018-03-01 9999-12-31
150 99 video True 2 intro 11.99 2018-03-01 9999-12-31

151 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 115 audio True 1 base 8.99 2018-09-01 9999-12-31
1 202 audio True 1 base 8.99 2018-11-01 9999-12-31
2 239 video False 1 base 10.99 2019-06-01 9999-12-31
3 419 video False 1 base 10.99 2019-06-01 9999-12-31
4 426 audio True 1 base 8.99 2019-03-01 9999-12-31
5 426 video True 1 base 10.99 2019-03-01 9999-12-31
6 543 audio True 2 base 12.99 2019-05-01 9999-12-31
7 640 audio False 1 intro 5.99 2019-06-01 9999-12-31
8 640 video False 1 intro 8.99 2019-06-01 9999-12-31
9 690 video True 1 intro 8.99 2019-02-01 9999-12-31
10 710 audio False 1 intro 5.99 2019-06-01 9999-12-31
11 731 audio True 1 intro 5.99 2019-03-01 9999-12-31
12 731 video True 1 intro 8.99 2019-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 10 True video 2 base 15.99 2018-08-01 9999-12-31
3 100 True audio 2 base 12.99 2018-09-01 9999-12-31
4 101 True audio 1 base 8.99 2018-12-01 9999-12-31
... ... ... ... ... ... ... ... ...
1100 95 True video 1 base 10.99 2018-09-01 9999-12-31
1101 96 True audio 2 base 12.99 2018-09-01 9999-12-31
1102 97 True audio 2 base 12.99 2018-09-01 9999-12-31
1103 98 True video 1 base 10.99 2018-09-01 9999-12-31
1104 99 True audio 1 base 8.99 2018-09-01 9999-12-31

1105 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 10 video True 2 base 15.99 2018-08-01 9999-12-31
3 100 audio True 2 base 12.99 2018-09-01 9999-12-31
4 101 audio True 1 base 8.99 2018-12-01 9999-12-31
... ... ... ... ... ... ... ... ...
1100 95 video True 1 base 10.99 2018-09-01 9999-12-31
1101 96 audio True 2 base 12.99 2018-09-01 9999-12-31
1102 97 audio True 2 base 12.99 2018-09-01 9999-12-31
1103 98 video True 1 base 10.99 2018-09-01 9999-12-31
1104 99 audio True 1 base 8.99 2018-09-01 9999-12-31

1105 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 142 video True 2 base 15.99 2018-10-01 9999-12-31
1 157 audio True 1 base 8.99 2018-10-01 9999-12-31
2 157 video True 1 base 10.99 2018-10-01 9999-12-31
3 221 video True 2 intro 11.99 2018-06-01 9999-12-31
4 23 video True 1 base 10.99 2018-08-01 9999-12-31
5 234 video True 1 intro 8.99 2018-07-01 9999-12-31
6 271 audio True 1 intro 5.99 2018-08-01 9999-12-31
7 279 video True 2 intro 11.99 2018-08-01 9999-12-31
8 344 video True 1 intro 8.99 2018-09-01 9999-12-31
9 392 audio True 1 intro 5.99 2018-10-01 9999-12-31
10 392 video True 1 intro 8.99 2018-10-01 9999-12-31
11 6 audio True 1 base 8.99 2018-08-01 9999-12-31
12 6 video True 1 base 10.99 2018-08-01 9999-12-31
13 68 audio True 2 base 12.99 2018-09-01 9999-12-31
14 68 video True 2 base 15.99 2018-09-01 9999-12-31
15 91 audio False 2 base 12.99 2018-10-01 9999-12-31
16 91 video False 2 base 15.99 2018-10-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 1 True audio 1 base 8.99 2018-08-01 9999-12-31
3 10 True audio 2 base 12.99 2018-08-01 9999-12-31
4 100 True audio 1 base 8.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
497 96 True audio 2 base 12.99 2018-09-01 9999-12-31
498 97 True audio 2 base 12.99 2018-09-01 9999-12-31
499 97 True video 2 base 15.99 2018-09-01 9999-12-31
500 99 True audio 2 base 12.99 2018-09-01 9999-12-31
501 99 True video 2 base 15.99 2018-09-01 9999-12-31

502 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 1 audio True 1 base 8.99 2018-08-01 9999-12-31
3 10 audio True 2 base 12.99 2018-08-01 9999-12-31
4 100 audio True 1 base 8.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
497 96 audio True 2 base 12.99 2018-09-01 9999-12-31
498 97 audio True 2 base 12.99 2018-09-01 9999-12-31
499 97 video True 2 base 15.99 2018-09-01 9999-12-31
500 99 audio True 2 base 12.99 2018-09-01 9999-12-31
501 99 video True 2 base 15.99 2018-09-01 9999-12-31

502 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 149 video True 2 intro 11.99 2018-04-01 9999-12-31
1 170 audio False 1 intro 5.99 2018-08-01 9999-12-31
2 205 audio True 2 intro 9.99 2018-08-01 9999-12-31
3 205 video True 2 intro 11.99 2018-08-01 9999-12-31
4 208 audio True 1 intro 5.99 2018-07-01 9999-12-31
5 208 video True 1 intro 8.99 2018-07-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 2 base 12.99 2018-08-01 9999-12-31
1 1 True audio 1 base 8.99 2018-08-01 9999-12-31
2 1 True video 1 base 10.99 2018-08-01 9999-12-31
3 10 True audio 1 base 8.99 2018-08-01 9999-12-31
4 10 True video 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
384 95 True video 1 base 10.99 2018-03-01 9999-12-31
385 96 True audio 1 base 8.99 2018-03-01 9999-12-31
386 97 True video 1 intro 8.99 2018-04-01 9999-12-31
387 98 True audio 2 intro 9.99 2018-04-01 9999-12-31
388 99 True audio 1 intro 5.99 2018-04-01 9999-12-31

389 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 2 base 12.99 2018-08-01 9999-12-31
1 1 audio True 1 base 8.99 2018-08-01 9999-12-31
2 1 video True 1 base 10.99 2018-08-01 9999-12-31
3 10 audio True 1 base 8.99 2018-08-01 9999-12-31
4 10 video True 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
384 95 video True 1 intro 8.99 2018-03-01 9999-12-31
385 96 audio True 1 intro 5.99 2018-03-01 9999-12-31
386 97 video True 1 intro 8.99 2018-04-01 9999-12-31
387 98 audio True 2 intro 9.99 2018-04-01 9999-12-31
388 99 audio True 1 intro 5.99 2018-04-01 9999-12-31

389 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 107 video True 2 intro 11.99 2018-03-01 9999-12-31
1 59 audio True 1 intro 5.99 2018-03-01 9999-12-31
2 63 audio True 1 intro 5.99 2018-03-01 9999-12-31
3 80 audio True 2 intro 9.99 2018-03-01 9999-12-31
4 80 video True 2 intro 11.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 0 True video 1 intro 8.99 2018-02-01 9999-12-31
2 1 True audio 2 intro 9.99 2018-02-01 9999-12-31
3 10 True audio 2 intro 9.99 2018-02-01 9999-12-31
4 10 True video 2 intro 11.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
230 97 True audio 1 intro 5.99 2018-03-01 9999-12-31
231 97 True video 1 intro 8.99 2018-03-01 9999-12-31
232 98 True video 2 intro 11.99 2018-03-01 9999-12-31
233 99 True audio 2 intro 9.99 2018-03-01 9999-12-31
234 99 True video 2 intro 11.99 2018-03-01 9999-12-31

235 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 0 video True 1 intro 8.99 2018-02-01 9999-12-31
2 1 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 10 audio True 2 intro 9.99 2018-02-01 9999-12-31
4 10 video True 2 intro 11.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
230 97 audio True 1 intro 5.99 2018-03-01 9999-12-31
231 97 video True 1 intro 8.99 2018-03-01 9999-12-31
232 98 video True 2 intro 11.99 2018-03-01 9999-12-31
233 99 audio True 2 intro 9.99 2018-03-01 9999-12-31
234 99 video True 2 intro 11.99 2018-03-01 9999-12-31

235 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 151 audio True 1 intro 5.99 2018-04-01 9999-12-31
1 151 video True 1 intro 8.99 2018-04-01 9999-12-31
2 270 audio False 1 intro 5.99 2018-08-01 9999-12-31
3 275 audio False 1 intro 5.99 2018-08-01 9999-12-31
4 55 audio False 2 intro 9.99 2018-08-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 1 True video 2 base 15.99 2018-08-01 9999-12-31
2 10 True video 1 base 10.99 2018-08-01 9999-12-31
3 100 True audio 1 intro 5.99 2018-04-01 9999-12-31
4 101 True video 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
382 95 True video 1 base 10.99 2018-03-01 9999-12-31
383 96 True audio 1 intro 5.99 2018-04-01 9999-12-31
384 97 True video 2 intro 11.99 2018-04-01 9999-12-31
385 98 True audio 1 intro 5.99 2018-04-01 9999-12-31
386 99 True video 2 intro 11.99 2018-04-01 9999-12-31

387 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 1 video True 2 base 15.99 2018-08-01 9999-12-31
2 10 video True 1 base 10.99 2018-08-01 9999-12-31
3 100 audio True 1 intro 5.99 2018-04-01 9999-12-31
4 101 video True 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
382 95 video True 1 intro 8.99 2018-03-01 9999-12-31
383 96 audio True 1 intro 5.99 2018-04-01 9999-12-31
384 97 video True 2 intro 11.99 2018-04-01 9999-12-31
385 98 audio True 1 intro 5.99 2018-04-01 9999-12-31
386 99 video True 2 intro 11.99 2018-04-01 9999-12-31

387 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 118 video False 1 intro 8.99 2018-05-01 9999-12-31
1 154 audio True 1 intro 5.99 2018-05-01 9999-12-31
2 62 audio True 2 intro 9.99 2018-03-01 9999-12-31
3 81 audio True 1 intro 5.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 2 intro 9.99 2018-02-01 9999-12-31
1 1 True audio 1 intro 5.99 2018-02-01 9999-12-31
2 1 True video 1 intro 8.99 2018-02-01 9999-12-31
3 10 True audio 1 intro 5.99 2018-02-01 9999-12-31
4 10 True video 1 intro 8.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
223 95 True video 1 intro 8.99 2018-03-01 9999-12-31
224 96 True audio 1 intro 5.99 2018-03-01 9999-12-31
225 97 True video 1 intro 8.99 2018-04-01 9999-12-31
226 98 True audio 2 intro 9.99 2018-04-01 9999-12-31
227 99 True audio 1 intro 5.99 2018-04-01 9999-12-31

228 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 2 intro 9.99 2018-02-01 9999-12-31
1 1 audio True 1 intro 5.99 2018-02-01 9999-12-31
2 1 video True 1 intro 8.99 2018-02-01 9999-12-31
3 10 audio True 1 intro 5.99 2018-02-01 9999-12-31
4 10 video True 1 intro 8.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
223 95 video True 1 intro 8.99 2018-03-01 9999-12-31
224 96 audio True 1 intro 5.99 2018-03-01 9999-12-31
225 97 video True 1 intro 8.99 2018-04-01 9999-12-31
226 98 audio True 2 intro 9.99 2018-04-01 9999-12-31
227 99 audio True 1 intro 5.99 2018-04-01 9999-12-31

228 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 130 audio True 1 intro 5.99 2018-04-01 9999-12-31
1 168 video True 2 intro 11.99 2018-05-01 9999-12-31
2 227 audio True 2 intro 9.99 2018-06-01 9999-12-31
3 227 video True 2 intro 11.99 2018-06-01 9999-12-31
4 244 video False 1 intro 8.99 2018-07-01 9999-12-31
5 88 audio True 1 intro 5.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-02-01 9999-12-31
1 1 True video 2 base 15.99 2018-02-01 9999-12-31
2 10 True video 1 base 10.99 2018-02-01 9999-12-31
3 100 True audio 1 intro 5.99 2018-04-01 9999-12-31
4 101 True video 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
352 95 True video 1 intro 8.99 2018-03-01 9999-12-31
353 96 True audio 1 intro 5.99 2018-04-01 9999-12-31
354 97 True video 2 intro 11.99 2018-04-01 9999-12-31
355 98 True audio 1 intro 5.99 2018-04-01 9999-12-31
356 99 True video 2 intro 11.99 2018-04-01 9999-12-31

357 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 1 video True 2 intro 11.99 2018-02-01 9999-12-31
2 10 video True 1 intro 8.99 2018-02-01 9999-12-31
3 100 audio True 1 intro 5.99 2018-04-01 9999-12-31
4 101 video True 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
352 95 video True 1 intro 8.99 2018-03-01 9999-12-31
353 96 audio True 1 intro 5.99 2018-04-01 9999-12-31
354 97 video True 2 intro 11.99 2018-04-01 9999-12-31
355 98 audio True 1 intro 5.99 2018-04-01 9999-12-31
356 99 video True 2 intro 11.99 2018-04-01 9999-12-31

357 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 106 audio True 1 intro 5.99 2018-03-01 9999-12-31
1 106 video True 1 intro 8.99 2018-03-01 9999-12-31
2 113 audio True 2 intro 9.99 2018-04-01 9999-12-31
3 52 audio False 1 intro 5.99 2018-05-01 9999-12-31
4 61 audio True 2 intro 9.99 2018-03-01 9999-12-31
5 61 video True 2 intro 11.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 0 True video 1 intro 8.99 2018-02-01 9999-12-31
2 1 True audio 1 intro 5.99 2018-02-01 9999-12-31
3 1 True video 1 intro 8.99 2018-02-01 9999-12-31
4 10 True video 1 intro 8.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
286 97 True audio 2 intro 9.99 2018-03-01 9999-12-31
287 97 True video 2 intro 11.99 2018-03-01 9999-12-31
288 98 True audio 1 intro 5.99 2018-03-01 9999-12-31
289 99 True audio 2 intro 9.99 2018-03-01 9999-12-31
290 99 True video 2 intro 11.99 2018-03-01 9999-12-31

291 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 0 video True 1 intro 8.99 2018-02-01 9999-12-31
2 1 audio True 1 intro 5.99 2018-02-01 9999-12-31
3 1 video True 1 intro 8.99 2018-02-01 9999-12-31
4 10 video True 1 intro 8.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
286 97 audio True 2 intro 9.99 2018-03-01 9999-12-31
287 97 video True 2 intro 11.99 2018-03-01 9999-12-31
288 98 audio True 1 intro 5.99 2018-03-01 9999-12-31
289 99 audio True 2 intro 9.99 2018-03-01 9999-12-31
290 99 video True 2 intro 11.99 2018-03-01 9999-12-31

291 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 142 video True 2 base 15.99 2018-10-01 9999-12-31
1 157 audio True 1 base 8.99 2018-10-01 9999-12-31
2 157 video True 1 base 10.99 2018-10-01 9999-12-31
3 221 video True 2 intro 11.99 2018-06-01 9999-12-31
4 23 video True 1 base 10.99 2018-08-01 9999-12-31
5 234 video True 1 intro 8.99 2018-07-01 9999-12-31
6 271 audio True 1 intro 5.99 2018-08-01 9999-12-31
7 279 video True 2 intro 11.99 2018-08-01 9999-12-31
8 344 video True 1 intro 8.99 2018-09-01 9999-12-31
9 392 audio True 1 intro 5.99 2018-10-01 9999-12-31
10 392 video True 1 intro 8.99 2018-10-01 9999-12-31
11 6 audio True 1 base 8.99 2018-08-01 9999-12-31
12 6 video True 1 base 10.99 2018-08-01 9999-12-31
13 68 audio True 2 base 12.99 2018-09-01 9999-12-31
14 68 video True 2 base 15.99 2018-09-01 9999-12-31
15 91 audio False 2 base 12.99 2018-10-01 9999-12-31
16 91 video False 2 base 15.99 2018-10-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 1 True audio 1 base 8.99 2018-08-01 9999-12-31
3 10 True audio 2 base 12.99 2018-08-01 9999-12-31
4 100 True audio 1 base 8.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
497 96 True audio 2 base 12.99 2018-09-01 9999-12-31
498 97 True audio 2 base 12.99 2018-09-01 9999-12-31
499 97 True video 2 base 15.99 2018-09-01 9999-12-31
500 99 True audio 2 base 12.99 2018-09-01 9999-12-31
501 99 True video 2 base 15.99 2018-09-01 9999-12-31

502 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 1 audio True 1 base 8.99 2018-08-01 9999-12-31
3 10 audio True 2 base 12.99 2018-08-01 9999-12-31
4 100 audio True 1 base 8.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
497 96 audio True 2 base 12.99 2018-09-01 9999-12-31
498 97 audio True 2 base 12.99 2018-09-01 9999-12-31
499 97 video True 2 base 15.99 2018-09-01 9999-12-31
500 99 audio True 2 base 12.99 2018-09-01 9999-12-31
501 99 video True 2 base 15.99 2018-09-01 9999-12-31

502 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 151 audio True 1 intro 5.99 2018-04-01 9999-12-31
1 151 video True 1 intro 8.99 2018-04-01 9999-12-31
2 270 audio False 1 intro 5.99 2018-08-01 9999-12-31
3 275 audio False 1 intro 5.99 2018-08-01 9999-12-31
4 55 audio False 2 intro 9.99 2018-08-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 1 True video 2 base 15.99 2018-08-01 9999-12-31
2 10 True video 1 base 10.99 2018-08-01 9999-12-31
3 100 True audio 1 intro 5.99 2018-04-01 9999-12-31
4 101 True video 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
382 95 True video 1 base 10.99 2018-03-01 9999-12-31
383 96 True audio 1 intro 5.99 2018-04-01 9999-12-31
384 97 True video 2 intro 11.99 2018-04-01 9999-12-31
385 98 True audio 1 intro 5.99 2018-04-01 9999-12-31
386 99 True video 2 intro 11.99 2018-04-01 9999-12-31

387 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 1 video True 2 base 15.99 2018-08-01 9999-12-31
2 10 video True 1 base 10.99 2018-08-01 9999-12-31
3 100 audio True 1 intro 5.99 2018-04-01 9999-12-31
4 101 video True 2 intro 11.99 2018-04-01 9999-12-31
... ... ... ... ... ... ... ... ...
382 95 video True 1 intro 8.99 2018-03-01 9999-12-31
383 96 audio True 1 intro 5.99 2018-04-01 9999-12-31
384 97 video True 2 intro 11.99 2018-04-01 9999-12-31
385 98 audio True 1 intro 5.99 2018-04-01 9999-12-31
386 99 video True 2 intro 11.99 2018-04-01 9999-12-31

387 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 145 audio False 1 base 8.99 2019-03-01 9999-12-31
1 145 video False 1 base 10.99 2019-03-01 9999-12-31
2 250 video True 1 base 10.99 2018-12-01 9999-12-31
3 253 audio False 1 base 8.99 2019-03-01 9999-12-31
4 253 video False 1 base 10.99 2019-03-01 9999-12-31
5 293 video True 1 base 10.99 2019-01-01 9999-12-31
6 510 audio True 1 intro 5.99 2018-11-01 9999-12-31
7 510 video True 1 intro 8.99 2018-11-01 9999-12-31
8 538 audio False 1 intro 5.99 2019-03-01 9999-12-31
9 593 audio True 1 intro 5.99 2018-12-01 9999-12-31
10 613 audio True 1 intro 5.99 2019-01-01 9999-12-31
11 613 video True 1 intro 8.99 2019-01-01 9999-12-31
12 630 audio True 1 intro 5.99 2019-01-01 9999-12-31
13 668 audio True 1 intro 5.99 2019-02-01 9999-12-31
14 709 video True 1 intro 8.99 2019-03-01 9999-12-31
15 91 video True 1 base 10.99 2018-09-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 1 True audio 1 base 8.99 2018-08-01 9999-12-31
3 1 True video 1 base 10.99 2018-08-01 9999-12-31
4 10 True video 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
867 96 True video 1 base 10.99 2018-09-01 9999-12-31
868 97 True audio 2 base 12.99 2018-09-01 9999-12-31
869 97 True video 2 base 15.99 2018-09-01 9999-12-31
870 99 True audio 2 base 12.99 2018-09-01 9999-12-31
871 99 True video 2 base 15.99 2018-09-01 9999-12-31

872 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 1 audio True 1 base 8.99 2018-08-01 9999-12-31
3 1 video True 1 base 10.99 2018-08-01 9999-12-31
4 10 video True 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
867 96 video True 1 base 10.99 2018-09-01 9999-12-31
868 97 audio True 2 base 12.99 2018-09-01 9999-12-31
869 97 video True 2 base 15.99 2018-09-01 9999-12-31
870 99 audio True 2 base 12.99 2018-09-01 9999-12-31
871 99 video True 2 base 15.99 2018-09-01 9999-12-31

872 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 20 audio True 1 base 8.99 2018-08-01 9999-12-31
1 309 audio True 1 intro 5.99 2018-07-01 9999-12-31
2 343 audio True 2 intro 9.99 2018-08-01 9999-12-31
3 343 video True 2 intro 11.99 2018-08-01 9999-12-31
4 472 audio True 2 intro 9.99 2018-10-01 9999-12-31
5 472 video True 2 intro 11.99 2018-10-01 9999-12-31
6 64 audio True 1 base 8.99 2018-09-01 9999-12-31
7 91 video True 1 base 10.99 2018-09-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 10 True video 2 base 15.99 2018-08-01 9999-12-31
3 100 True audio 2 base 12.99 2018-09-01 9999-12-31
4 101 True audio 2 base 12.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
642 95 True video 1 base 10.99 2018-09-01 9999-12-31
643 96 True audio 2 base 12.99 2018-09-01 9999-12-31
644 97 True audio 2 base 12.99 2018-09-01 9999-12-31
645 98 True video 1 base 10.99 2018-09-01 9999-12-31
646 99 True audio 1 base 8.99 2018-09-01 9999-12-31

647 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 10 video True 2 base 15.99 2018-08-01 9999-12-31
3 100 audio True 2 base 12.99 2018-09-01 9999-12-31
4 101 audio True 2 base 12.99 2018-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
642 95 video True 1 base 10.99 2018-09-01 9999-12-31
643 96 audio True 2 base 12.99 2018-09-01 9999-12-31
644 97 audio True 2 base 12.99 2018-09-01 9999-12-31
645 98 video True 1 base 10.99 2018-09-01 9999-12-31
646 99 audio True 1 base 8.99 2018-09-01 9999-12-31

647 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 3 audio True 2 intro 9.99 2018-02-01 9999-12-31
1 3 video True 2 intro 11.99 2018-02-01 9999-12-31
2 35 video False 1 intro 8.99 2018-03-01 9999-12-31
3 37 audio False 2 intro 9.99 2018-03-01 9999-12-31
4 55 audio True 1 intro 5.99 2018-03-01 9999-12-31
5 55 video True 1 intro 8.99 2018-03-01 9999-12-31
6 65 audio True 1 intro 5.99 2018-03-01 9999-12-31
7 65 video True 1 intro 8.99 2018-03-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 intro 5.99 2018-02-01 9999-12-31
1 0 True video 1 intro 8.99 2018-02-01 9999-12-31
2 1 True audio 2 intro 9.99 2018-02-01 9999-12-31
3 10 True audio 2 intro 9.99 2018-02-01 9999-12-31
4 10 True video 2 intro 11.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
176 97 True audio 1 intro 5.99 2018-03-01 9999-12-31
177 97 True video 1 intro 8.99 2018-03-01 9999-12-31
178 98 True video 2 intro 11.99 2018-03-01 9999-12-31
179 99 True audio 2 intro 9.99 2018-03-01 9999-12-31
180 99 True video 2 intro 11.99 2018-03-01 9999-12-31

181 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 intro 5.99 2018-02-01 9999-12-31
1 0 video True 1 intro 8.99 2018-02-01 9999-12-31
2 1 audio True 2 intro 9.99 2018-02-01 9999-12-31
3 10 audio True 2 intro 9.99 2018-02-01 9999-12-31
4 10 video True 2 intro 11.99 2018-02-01 9999-12-31
... ... ... ... ... ... ... ... ...
176 97 audio True 1 intro 5.99 2018-03-01 9999-12-31
177 97 video True 1 intro 8.99 2018-03-01 9999-12-31
178 98 video True 2 intro 11.99 2018-03-01 9999-12-31
179 99 audio True 2 intro 9.99 2018-03-01 9999-12-31
180 99 video True 2 intro 11.99 2018-03-01 9999-12-31

181 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 31 audio False 1 base 8.99 2019-09-01 9999-12-31
1 31 video False 1 base 10.99 2019-09-01 9999-12-31
2 344 video True 2 base 15.99 2019-02-01 9999-12-31
3 384 audio False 1 base 8.99 2019-09-01 9999-12-31
4 384 video False 1 base 10.99 2019-09-01 9999-12-31
5 430 video False 2 base 15.99 2019-09-01 9999-12-31
6 576 audio True 1 base 8.99 2019-07-01 9999-12-31
7 655 video False 1 base 10.99 2019-09-01 9999-12-31
8 7 audio True 1 base 8.99 2018-08-01 9999-12-31
9 734 audio True 1 intro 5.99 2019-04-01 9999-12-31
10 734 video True 1 intro 8.99 2019-04-01 9999-12-31
11 751 audio False 1 intro 5.99 2019-09-01 9999-12-31
12 751 video False 1 intro 8.99 2019-09-01 9999-12-31
13 780 audio True 1 intro 5.99 2019-08-01 9999-12-31
14 783 video True 1 intro 8.99 2019-04-01 9999-12-31
15 799 video True 2 intro 11.99 2019-05-01 9999-12-31
16 953 audio True 1 intro 5.99 2019-08-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 2 base 12.99 2018-08-01 9999-12-31
1 0 True video 2 base 15.99 2018-08-01 9999-12-31
2 1 True video 1 base 10.99 2018-08-01 9999-12-31
3 100 True audio 1 base 8.99 2018-09-01 9999-12-31
4 1000 True video 1 intro 8.99 2019-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
1193 995 True video 1 intro 8.99 2019-09-01 9999-12-31
1194 996 True audio 1 intro 5.99 2019-09-01 9999-12-31
1195 997 True audio 1 intro 5.99 2019-09-01 9999-12-31
1196 998 True audio 2 intro 9.99 2019-09-01 9999-12-31
1197 999 True audio 1 intro 5.99 2019-09-01 9999-12-31

1198 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 2 base 12.99 2018-08-01 9999-12-31
1 0 video True 2 base 15.99 2018-08-01 9999-12-31
2 1 video True 1 base 10.99 2018-08-01 9999-12-31
3 100 audio True 1 base 8.99 2018-09-01 9999-12-31
4 1000 video True 1 intro 8.99 2019-09-01 9999-12-31
... ... ... ... ... ... ... ... ...
1193 995 video True 1 intro 8.99 2019-09-01 9999-12-31
1194 996 audio True 1 intro 5.99 2019-09-01 9999-12-31
1195 997 audio True 1 intro 5.99 2019-09-01 9999-12-31
1196 998 audio True 2 intro 9.99 2019-09-01 9999-12-31
1197 999 audio True 1 intro 5.99 2019-09-01 9999-12-31

1198 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
id paid service tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
id service paid tier promo price eff_dt exp_dt
0 149 video True 2 intro 11.99 2018-04-01 9999-12-31
1 170 audio False 1 intro 5.99 2018-08-01 9999-12-31
2 205 audio True 2 intro 9.99 2018-08-01 9999-12-31
3 205 video True 2 intro 11.99 2018-08-01 9999-12-31
4 208 audio True 1 intro 5.99 2018-07-01 9999-12-31
5 208 video True 1 intro 8.99 2018-07-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 2 base 12.99 2018-08-01 9999-12-31
1 1 True audio 1 base 8.99 2018-08-01 9999-12-31
2 1 True video 1 base 10.99 2018-08-01 9999-12-31
3 10 True audio 1 base 8.99 2018-08-01 9999-12-31
4 10 True video 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
384 95 True video 1 base 10.99 2018-03-01 9999-12-31
385 96 True audio 1 base 8.99 2018-03-01 9999-12-31
386 97 True video 1 intro 8.99 2018-04-01 9999-12-31
387 98 True audio 2 intro 9.99 2018-04-01 9999-12-31
388 99 True audio 1 intro 5.99 2018-04-01 9999-12-31

389 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 2 base 12.99 2018-08-01 9999-12-31
1 1 audio True 1 base 8.99 2018-08-01 9999-12-31
2 1 video True 1 base 10.99 2018-08-01 9999-12-31
3 10 audio True 1 base 8.99 2018-08-01 9999-12-31
4 10 video True 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
384 95 video True 1 intro 8.99 2018-03-01 9999-12-31
385 96 audio True 1 intro 5.99 2018-03-01 9999-12-31
386 97 video True 1 intro 8.99 2018-04-01 9999-12-31
387 98 audio True 2 intro 9.99 2018-04-01 9999-12-31
388 99 audio True 1 intro 5.99 2018-04-01 9999-12-31

389 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 145 audio False 1 base 8.99 2019-03-01 9999-12-31
1 145 video False 1 base 10.99 2019-03-01 9999-12-31
2 250 video True 1 base 10.99 2018-12-01 9999-12-31
3 253 audio False 1 base 8.99 2019-03-01 9999-12-31
4 253 video False 1 base 10.99 2019-03-01 9999-12-31
5 293 video True 1 base 10.99 2019-01-01 9999-12-31
6 510 audio True 1 intro 5.99 2018-11-01 9999-12-31
7 510 video True 1 intro 8.99 2018-11-01 9999-12-31
8 538 audio False 1 intro 5.99 2019-03-01 9999-12-31
9 593 audio True 1 intro 5.99 2018-12-01 9999-12-31
10 613 audio True 1 intro 5.99 2019-01-01 9999-12-31
11 613 video True 1 intro 8.99 2019-01-01 9999-12-31
12 630 audio True 1 intro 5.99 2019-01-01 9999-12-31
13 668 audio True 1 intro 5.99 2019-02-01 9999-12-31
14 709 video True 1 intro 8.99 2019-03-01 9999-12-31
15 91 video True 1 base 10.99 2018-09-01 9999-12-31
id paid service tier promo price eff_dt exp_dt
0 0 True audio 1 base 8.99 2018-08-01 9999-12-31
1 0 True video 1 base 10.99 2018-08-01 9999-12-31
2 1 True audio 1 base 8.99 2018-08-01 9999-12-31
3 1 True video 1 base 10.99 2018-08-01 9999-12-31
4 10 True video 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
867 96 True video 1 base 10.99 2018-09-01 9999-12-31
868 97 True audio 2 base 12.99 2018-09-01 9999-12-31
869 97 True video 2 base 15.99 2018-09-01 9999-12-31
870 99 True audio 2 base 12.99 2018-09-01 9999-12-31
871 99 True video 2 base 15.99 2018-09-01 9999-12-31

872 rows × 8 columns

id service paid tier promo price eff_dt exp_dt
0 0 audio True 1 base 8.99 2018-08-01 9999-12-31
1 0 video True 1 base 10.99 2018-08-01 9999-12-31
2 1 audio True 1 base 8.99 2018-08-01 9999-12-31
3 1 video True 1 base 10.99 2018-08-01 9999-12-31
4 10 video True 1 base 10.99 2018-08-01 9999-12-31
... ... ... ... ... ... ... ... ...
867 96 video True 1 base 10.99 2018-09-01 9999-12-31
868 97 audio True 2 base 12.99 2018-09-01 9999-12-31
869 97 video True 2 base 15.99 2018-09-01 9999-12-31
870 99 audio True 2 base 12.99 2018-09-01 9999-12-31
871 99 video True 2 base 15.99 2018-09-01 9999-12-31

872 rows × 8 columns

This test executed in 10 seconds
Passed! Please submit.

Exercise 5 - (3 Points):

Motivation (don't dwell on this):
Our next task is to identify records which have changed and which records are unchanged. These are a subset of records having keys in both the business data and the active journal. We need to partition both the business data and journal data into two parts based on whether the data has changed.

Requirements:
Define compare_changes(compare_new_df, compare_old_df, audit_cols).

The inputs are as follows:

  • compare_new_df - a DataFrame
  • compare_old_df - another DataFrame with the same columns/shape/indexing as compare_new_df
  • audit_cols - a list of column names which should not be used for comparison.

You can assume that the rows compare_new_df and compare_old_df are sorted and indexed such that they can be compared directly.

  • Identify the columns in compare_new_df which are not in audit_cols. Let's call this cols.
  • Compare the values in compare_new_df[cols] with the values in compare_old_df[cols].
  • Return these 3 new DataFrames:
    • unchanged - All of the rows in compare_new_df where all values are the same in the comparison.
    • old_changed - All of the rows in compare_old_df where there are any differences in the comparison.
    • new_changed - All of the rows in compare_new_df where there are any differences in the comparison.

It is possible that compare_new_df and compare_old_df are both empty DataFrames. If this is the case all 3 returned DataFrames would also be empty.

In [61]:
### Define demo inputs

demo_compare_new_df_ex5 = pd.DataFrame([
    {'some_column': 'new_val_0', 'key_column': 'changed_0', 'audit_column_1': None, 'audit_column_2': None},
    {'some_column': 'new_val_1', 'key_column': 'changed_1', 'audit_column_1': None, 'audit_column_2': None},
    {'some_column': 'same_val_0', 'key_column': 'unchanged_0', 'audit_column_1': None, 'audit_column_2': None},
    {'some_column': 'same_val_1', 'key_column': 'unchanged_1', 'audit_column_1': None, 'audit_column_2': None},
    {'some_column': 'new_val_2', 'key_column': 'changed_2', 'audit_column_1': None, 'audit_column_2': None},
    {'some_column': 'same_val_2', 'key_column': 'unchanged_2', 'audit_column_1': None, 'audit_column_2': None}
])

demo_compare_old_df_ex5 = pd.DataFrame([
    {'some_column': 'old_val_0', 'key_column': 'changed_0', 'audit_column_1': 'foo', 'audit_column_2': 'bar'},
    {'some_column': 'old_val_1', 'key_column': 'changed_1', 'audit_column_1': 'foo', 'audit_column_2': 'bar'},
    {'some_column': 'same_val_0', 'key_column': 'unchanged_0', 'audit_column_1': 'foo', 'audit_column_2': 'bar'},
    {'some_column': 'same_val_1', 'key_column': 'unchanged_1', 'audit_column_1': 'foo', 'audit_column_2': 'bar'},
    {'some_column': 'old_val_2', 'key_column': 'changed_2', 'audit_column_1': 'foo', 'audit_column_2': 'bar'},
    {'some_column': 'same_val_2', 'key_column': 'unchanged_2', 'audit_column_1': 'foo', 'audit_column_2': 'bar'}
])

demo_audit_cols_ex5 = ['audit_column_1', 'audit_column_2']

print('compare_new_df')
print(demo_compare_new_df_ex5)
print()
print('compare_old_df')
print(demo_compare_old_df_ex5)
print()
print('audit_cols')
print(demo_audit_cols_ex5)
compare_new_df
  some_column   key_column audit_column_1 audit_column_2
0   new_val_0    changed_0           None           None
1   new_val_1    changed_1           None           None
2  same_val_0  unchanged_0           None           None
3  same_val_1  unchanged_1           None           None
4   new_val_2    changed_2           None           None
5  same_val_2  unchanged_2           None           None

compare_old_df
  some_column   key_column audit_column_1 audit_column_2
0   old_val_0    changed_0            foo            bar
1   old_val_1    changed_1            foo            bar
2  same_val_0  unchanged_0            foo            bar
3  same_val_1  unchanged_1            foo            bar
4   old_val_2    changed_2            foo            bar
5  same_val_2  unchanged_2            foo            bar

audit_cols
['audit_column_1', 'audit_column_2']
The demo included in the solution cell below should display the following output: ``` unchanged some_column key_column audit_column_1 audit_column_2 2 same_val_0 unchanged_0 None None 3 same_val_1 unchanged_1 None None 5 same_val_2 unchanged_2 None None old_changed some_column key_column audit_column_1 audit_column_2 0 old_val_0 changed_0 foo bar 1 old_val_1 changed_1 foo bar 4 old_val_2 changed_2 foo bar new_changed some_column key_column audit_column_1 audit_column_2 0 new_val_0 changed_0 None None 1 new_val_1 changed_1 None None 4 new_val_2 changed_2 None None ```
In [69]:
### Exercise 5 solution
def compare_changes(compare_new_df, compare_old_df, audit_cols):
    ###
    ### YOUR CODE HERE
    ###
    
    cols = [i for i in compare_new_df.columns if i not in audit_cols]
    print(cols)
    print(audit_cols)
    
    both = compare_new_df.merge(compare_old_df, on=cols)
    unchanged = drop_rename_sort(both, "_y", "_x", cols)
    
    changed = compare_new_df.merge(compare_old_df, )
    

# Run demo of function    
(demo_unchanged_ex5,
demo_old_changed_ex5,
demo_new_changed_ex5) = compare_changes(demo_compare_new_df_ex5, demo_compare_old_df_ex5, demo_audit_cols_ex5)
print('unchanged')
print(demo_unchanged_ex5)
print()
print('old_changed')
print(demo_old_changed_ex5)
print()
print('new_changed')
print(demo_new_changed_ex5)
['some_column', 'key_column']
['audit_column_1', 'audit_column_2']
some_column key_column audit_column_1 audit_column_2
0 same_val_0 unchanged_0 None None
1 same_val_1 unchanged_1 None None
2 same_val_2 unchanged_2 None None
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-69-39a8e238900f> in <module>
     15 
     16 # Run demo of function
---> 17 (demo_unchanged_ex5,
     18 demo_old_changed_ex5,
     19 demo_new_changed_ex5) = compare_changes(demo_compare_new_df_ex5, demo_compare_old_df_ex5, demo_audit_cols_ex5)

TypeError: cannot unpack non-iterable NoneType object

The cell below will test your solution for Exercise 5. The testing variables will be available for debugging under the following names in a dictionary format.

  • input_vars - Input variables for your solution.
  • original_input_vars - Copy of input variables from prior to running your solution. These should be the same as input_vars - otherwise the inputs were modified by your solution.
  • returned_output_vars - Outputs returned by your solution.
  • true_output_vars - The expected output. This should "match" returned_output_vars based on the question requirements - otherwise, your solution is not returning the correct output.
In [ ]:
### test_cell_ex5
exercise_start = time.time()
###
### AUTOGRADER TEST - DO NOT REMOVE
###
from tester_fw.testers import Tester

conf = {
    'case_file':'tc_5', 
    'func': compare_changes, # replace this with the function defined above
    'inputs':{ # input config dict. keys are parameter names
        'compare_new_df':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'compare_old_df':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'audit_cols':{
            'dtype':'list', # data type of param.
            'check_modified':True,
        }
    },
    'outputs':{
        'unchanged':{
            'index':0,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': False, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': False, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        },
        'old_changed':{
            'index':1,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': False, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': False, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        },
        'new_changed':{
            'index':2,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': False, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': False, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        }
    }
}
tester = Tester(conf, key=b'6IRWMcPsVIAZqzDJnPgv_MfUZsxqo4Utjm2Favidv-A=', path='resource/asnlib/publicdata/')
for _ in range(70):
    try:
        tester.run_test()
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
    except:
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
        raise

###
### AUTOGRADER TEST - DO NOT REMOVE
###
exercise_end = time.time()
print(f"This test executed in {(pd.to_datetime(exercise_end, unit='s') - pd.to_datetime(exercise_start, unit='s')).seconds} seconds")
print('Passed! Please submit.')

Exercise 6 - (1 Points):

Motivation (Don't dwell on this): So far we have sliced and diced the business data and journal data into several partitions. Some of these partitions will need to be added to the journal by setting the effective and expiration dates. Here we will write a generic function to set the effective date to the "data date" (date when the snapshot was taken) and set the expiration date to '9999-12-31' for an arbitrary partition.

Requirements: Define add_records(df, data_date)

The input df is a DataFrame which can be assumed to have columns 'eff_dt' and 'exp_dt'. The input data_date is a Pandas Timestamp object. The function should return a new DataFrame having the same data as df with the following exceptions:

  • The 'eff_dt' field should be set to the data_date as a string in 'YYYY-MM-DD' format for all records. See the docs for more information on performing this transformation.
  • The 'exp_dt' field should be set to '9999-12-31' for all records.

Note df may be empty!

In [ ]:
### Define demo inputs

demo_df_ex6 = pd.DataFrame([
    {'eff_dt':None, 'exp_dt':None, 'col0':'val_00', 'col1':'val01'},
    {'eff_dt':None, 'exp_dt':None, 'col0':'val_10', 'col1':'val11'},    
    {'eff_dt':None, 'exp_dt':None, 'col0':'val_20', 'col1':'val21'},        
])
print('df')
print(demo_df_ex6)
print()
demo_data_date_ex6 = pd.to_datetime('2020-10-15')
print('data_date')
print(type(demo_data_date_ex6))
print(demo_data_date_ex6)
The demo included in the solution cell below should display the following output: ``` eff_dt exp_dt col0 col1 0 2020-10-15 9999-12-31 val_00 val01 1 2020-10-15 9999-12-31 val_10 val11 2 2020-10-15 9999-12-31 val_20 val21 ```
In [ ]:
### Exercise 6 solution
def add_records(df, data_date):
    ###
    ### YOUR CODE HERE
    ###
    
### demo function call
print(add_records(demo_df_ex6, demo_data_date_ex6))

The cell below will test your solution for Exercise 6. The testing variables will be available for debugging under the following names in a dictionary format.

  • input_vars - Input variables for your solution.
  • original_input_vars - Copy of input variables from prior to running your solution. These should be the same as input_vars - otherwise the inputs were modified by your solution.
  • returned_output_vars - Outputs returned by your solution.
  • true_output_vars - The expected output. This should "match" returned_output_vars based on the question requirements - otherwise, your solution is not returning the correct output.
In [ ]:
### test_cell_ex6
exercise_start = time.time()
###
### AUTOGRADER TEST - DO NOT REMOVE
###
from tester_fw.testers import Tester

conf = {
    'case_file':'tc_6', 
    'func': add_records, # replace this with the function defined above
    'inputs':{ # input config dict. keys are parameter names
        'df':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'data_date':{
            'dtype':'Timestamp',
            'check_modified':False
        }
    },
    'outputs':{
        'output_0':{
            'index':0,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': False, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        }
    }
}
tester = Tester(conf, key=b'6IRWMcPsVIAZqzDJnPgv_MfUZsxqo4Utjm2Favidv-A=', path='resource/asnlib/publicdata/')
for _ in range(70):
    try:
        tester.run_test()
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
    except:
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
        raise

###
### AUTOGRADER TEST - DO NOT REMOVE
###
exercise_end = time.time()
print(f"This test executed in {(pd.to_datetime(exercise_end, unit='s') - pd.to_datetime(exercise_start, unit='s')).seconds} seconds")
print('Passed! Please submit.')

Exercise 7 - (2 Points):

Motivation (Don't dwell on this): So far we have sliced and diced the business data and journal data into several partitions. Some of these partitions will need to be expired in the journal by updating the expiration dates. Here we will write a generic function to set the expiration date to one day prior to the "data date" (date when the snapshot was taken).

Requirements: Define expire_records(df, data_date)

The input df is a DataFrame which can be assumed to have columns 'eff_dt' and 'exp_dt'. The input data_date is a Pandas Timestamp object. The function should return a new DataFrame having the same data as df with the following exceptions:

  • The 'exp_dt' field should be set to one day prior to the data_date as a string in 'YYYY-MM-DD' format for all records. See the stackoverflow or pandas docs for more information on math with Timestamps and strftime docs for more information on extracting the string.

You will want to use a module that accounts for changes in months, years, and leap-days for calculating the exp_dt.

Note - df may be empty!

In [ ]:
### Define demo inputs

demo_df_ex7 = pd.DataFrame([
    {'eff_dt':'0001-01-01', 'exp_dt':None, 'col0':'val_00', 'col1':'val01'},
    {'eff_dt':'0001-01-01', 'exp_dt':None, 'col0':'val_10', 'col1':'val11'},    
    {'eff_dt':'0001-01-01', 'exp_dt':None, 'col0':'val_20', 'col1':'val21'},        
])
print('df')
print(demo_df_ex7)
print()
demo_data_date_ex7 = pd.to_datetime('2020-03-01')
print('data_date')
print(type(demo_data_date_ex7))
print(demo_data_date_ex7)
The demo included in the solution cell below should display the following output: ``` eff_dt exp_dt col0 col1 0 0001-01-01 2020-02-29 val_00 val01 1 0001-01-01 2020-02-29 val_10 val11 2 0001-01-01 2020-02-29 val_20 val21 ```
In [ ]:
### Exercise 7 solution
def expire_records(df, data_date):
    ###
    ### YOUR CODE HERE
    ###
    
### demo function call
print(expire_records(demo_df_ex7, demo_data_date_ex7))

The cell below will test your solution for Exercise 7. The testing variables will be available for debugging under the following names in a dictionary format.

  • input_vars - Input variables for your solution.
  • original_input_vars - Copy of input variables from prior to running your solution. These should be the same as input_vars - otherwise the inputs were modified by your solution.
  • returned_output_vars - Outputs returned by your solution.
  • true_output_vars - The expected output. This should "match" returned_output_vars based on the question requirements - otherwise, your solution is not returning the correct output.
In [ ]:
### test_cell_ex7
exercise_start = time.time()
###
### AUTOGRADER TEST - DO NOT REMOVE
###
from tester_fw.testers import Tester

conf = {
    'case_file':'tc_7', 
    'func': expire_records, # replace this with the function defined above
    'inputs':{ # input config dict. keys are parameter names
        'df':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'data_date':{
            'dtype':'Timestamp',
            'check_modified':False
        }
    },
    'outputs':{
        'output_0':{
            'index':0,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': False, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        }
    }
}
tester = Tester(conf, key=b'6IRWMcPsVIAZqzDJnPgv_MfUZsxqo4Utjm2Favidv-A=', path='resource/asnlib/publicdata/')
for _ in range(70):
    try:
        tester.run_test()
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
    except:
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
        raise

###
### AUTOGRADER TEST - DO NOT REMOVE
###
exercise_end = time.time()
print(f"This test executed in {(pd.to_datetime(exercise_end, unit='s') - pd.to_datetime(exercise_start, unit='s')).seconds} seconds")
print('Passed! Please submit.')

Putting it all together

(Don't dwell on this)
With the functions we wrote in the past few exercises, we have everything we need to perform a type 2 journaling operation. Here's how it looks all put together:

def journal(df, key_cols, data_date, existing_journal=None):
    audit_cols = ['eff_dt', 'exp_dt']
    historical_journal, active_journal = partition_jrnl(df, audit_cols, existing_journal)
    new_df, expired_df, compare_new_df, compare_old_df = compare_to_journal(df, key_cols, active_journal)
    unchanged, old_changed, new_changed = compare_changes(compare_new_df, compare_old_df, audit_cols)

    new_records = add_records(new_df, data_date)
    new_changed_records = add_records(new_changed, data_date)
    expired_records = expire_records(expired_df, data_date)
    old_changed_records = expire_records(old_changed, data_date)

    return pd.concat([
        historical_journal,
        new_records,
        new_changed_records,
        expired_records,
        old_changed_records,
        unchanged
    ])

Exercise 8 - (2 Points):

Motivation (don't dwell on this):
Here's where all of the tedious work we did partitioning these DataFrames pays off. We can reconstruct a snapshot of any particular date from the journal! To do so we just filter the journal to keep only records whose effective date is on or before that date and whose expiration date is on or after that date.

Requirements: Define the function time_travel(journal, data_date) as follows:

The input journal is a DataFrame with columns 'eff_dt' and 'exp_dt' in addition other arbitrary columns. The input data_date is a string representing a date in 'YYYY-MM-DD' format. The function should return a new DataFrame containing all records where 'eff_dt' 'data_date' 'exp_dt'.

The 'eff_dt' and 'exp_dt' fields should not be included in the result.

Note: One convenient fact about storing dates as strings in 'YYYY-MM-DD' format is that you can compare the strings directly with <, <=, !=, ==, >=, > without converting to a more complicated data type!

In [ ]:
### Define demo inputs

demo_journal_ex8 = pd.DataFrame(
    {'id': {674: '10', 675: '10', 2057: '10', 2058: '10', 1307: '998', 1308: '998', 1003: '998', 1004: '998', 1163: '10', 1164: '10', 10: '998', 11: '998'}, 
    'paid': {674: 'True', 675: 'True', 2057: 'True', 2058: 'True', 1307: 'True', 1308: 'True', 1003: 'True', 1004: 'True', 1163: 'True', 1164: 'True', 
            10: 'False', 11: 'False'}, 
    'service': {674: 'video', 675: 'audio', 2057: 'video', 2058: 'audio', 1307: 'video', 1308: 'audio', 1003: 'video', 1004: 'audio', 1163: 'video', 
            1164: 'audio', 10: 'video', 11: 'audio'}, 
    'tier': {674: '1', 675: '1', 2057: '1', 2058: '1', 1307: '1', 1308: '1', 1003: '1', 1004: '1', 1163: '2', 1164: '2', 10: '1', 11: '1'}, 
    'promo': {674: 'intro', 675: 'intro', 2057: 'base', 2058: 'base', 1307: 'intro', 1308: 'intro', 1003: 'base', 1004: 'base', 1163: 'base', 
            1164: 'base', 10: 'base', 11: 'base'}, 
    'price': {674: '8.99', 675: '5.99', 2057: '10.99', 2058: '8.99', 1307: '8.99', 1308: '5.99', 1003: '10.99', 1004: '8.99', 1163: '15.99', 
        1164: '12.99', 10: '10.99', 11: '8.99'}, 
    'eff_dt': {674: '2018-02-01', 675: '2018-02-01', 2057: '2018-08-01', 2058: '2018-08-01', 1307: '2018-12-01', 1308: '2018-12-01', 
            1003: '2019-06-01', 1004: '2019-06-01', 1163: '2019-08-01', 1164: '2019-08-01', 10: '2019-10-01', 11: '2019-10-01'}, 
    'exp_dt': {674: '2018-07-31', 675: '2018-07-31', 2057: '2019-07-31', 2058: '2019-07-31', 1307: '2019-05-31', 1308: '2019-05-31', 
            1003: '2019-09-30', 1004: '2019-09-30', 1163: '9999-12-31', 1164: '9999-12-31', 10: '2019-10-31', 11: '2019-10-31'}})
print('journal')
print(demo_journal_ex8)

The demo included in the solution cell below should display the following output:

data_date: 2018-02-02
     id  paid service tier  promo price
674  10  True   video    1  intro  8.99
675  10  True   audio    1  intro  5.99

data_date: 2018-08-01
      id  paid service tier promo  price
2057  10  True   video    1  base  10.99
2058  10  True   audio    1  base   8.99

data_date: 2019-01-01
       id  paid service tier  promo  price
2057   10  True   video    1   base  10.99
2058   10  True   audio    1   base   8.99
1307  998  True   video    1  intro   8.99
1308  998  True   audio    1  intro   5.99

data_date: 2019-06-15
       id  paid service tier promo  price
2057   10  True   video    1  base  10.99
2058   10  True   audio    1  base   8.99
1003  998  True   video    1  base  10.99
1004  998  True   audio    1  base   8.99

Note - this demo runs your solution for several different data_date values. Each of the DataFrames displayed is from a single run.

In [ ]:
### Exercise 8 solution
def time_travel(journal, data_date):
    ###
    ### YOUR CODE HERE
    ###
    
### demo function call
for demo_data_date_ex8 in ['2018-02-02', '2018-08-01', '2019-01-01', '2019-06-15']:
    print(f'data_date: {demo_data_date_ex8}')
    print(time_travel(demo_journal_ex8, demo_data_date_ex8))
    print()

The cell below will test your solution for Exercise 8. The testing variables will be available for debugging under the following names in a dictionary format.

  • input_vars - Input variables for your solution.
  • original_input_vars - Copy of input variables from prior to running your solution. These should be the same as input_vars - otherwise the inputs were modified by your solution.
  • returned_output_vars - Outputs returned by your solution.
  • true_output_vars - The expected output. This should "match" returned_output_vars based on the question requirements - otherwise, your solution is not returning the correct output.
In [ ]:
### test_cell_ex8
exercise_start = time.time()
###
### AUTOGRADER TEST - DO NOT REMOVE
###
from tester_fw.testers import Tester

conf = {
    'case_file':'tc_8', 
    'func': time_travel, # replace this with the function defined above
    'inputs':{ # input config dict. keys are parameter names
        'journal':{
            'dtype':'pd.DataFrame', # data type of param.
            'check_modified':True,
        },
        'data_date':{
            'dtype':'str',
            'check_modified':False
        }
    },
    'outputs':{
        'output_0':{
            'index':0,
            'dtype':'pd.DataFrame',
            'check_dtype': True,
            'check_col_dtypes': True, # Ignored if dtype is not df
            'check_col_order': False, # Ignored if dtype is not df
            'check_row_order': False, # Ignored if dtype is not df
            'check_column_type': True, # Ignored if dtype is not df
            'float_tolerance': 10 ** (-6)
        }
    }
}
tester = Tester(conf, key=b'6IRWMcPsVIAZqzDJnPgv_MfUZsxqo4Utjm2Favidv-A=', path='resource/asnlib/publicdata/')
for _ in range(70):
    try:
        tester.run_test()
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
    except:
        (input_vars, original_input_vars, returned_output_vars, true_output_vars) = tester.get_test_vars()
        raise

###
### AUTOGRADER TEST - DO NOT REMOVE
###
print('Passed! Please submit.')
exercise_end = time.time()
print(f"This test executed in {(pd.to_datetime(exercise_end, unit='s') - pd.to_datetime(exercise_start, unit='s')).seconds} seconds")
overall_end = exercise_end
print(f"The exam executed in {(pd.to_datetime(overall_end, unit='s') - pd.to_datetime(overall_start, unit='s')).seconds} seconds")

Fin. If you have made it this far, congratulations on completing the exam. Don't forget to submit!