Joining Data Frames¶
Let us understand how to join Data Frames using Pandas.
%run 06_csv_to_pandas_data_frame.ipynb
orders
| order_id | order_date | order_customer_id | order_status | |
|---|---|---|---|---|
| 0 | 1 | 2013-07-25 00:00:00.0 | 11599 | CLOSED | 
| 1 | 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 
| 2 | 3 | 2013-07-25 00:00:00.0 | 12111 | COMPLETE | 
| 3 | 4 | 2013-07-25 00:00:00.0 | 8827 | CLOSED | 
| 4 | 5 | 2013-07-25 00:00:00.0 | 11318 | COMPLETE | 
| ... | ... | ... | ... | ... | 
| 68878 | 68879 | 2014-07-09 00:00:00.0 | 778 | COMPLETE | 
| 68879 | 68880 | 2014-07-13 00:00:00.0 | 1117 | COMPLETE | 
| 68880 | 68881 | 2014-07-19 00:00:00.0 | 2518 | PENDING_PAYMENT | 
| 68881 | 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 
| 68882 | 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 
68883 rows × 4 columns
order_items
| order_item_id | order_item_order_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|---|
| 0 | 1 | 1 | 957 | 1 | 299.98 | 299.98 | 
| 1 | 2 | 2 | 1073 | 1 | 199.99 | 199.99 | 
| 2 | 3 | 2 | 502 | 5 | 250.00 | 50.00 | 
| 3 | 4 | 2 | 403 | 1 | 129.99 | 129.99 | 
| 4 | 5 | 4 | 897 | 2 | 49.98 | 24.99 | 
| ... | ... | ... | ... | ... | ... | ... | 
| 172193 | 172194 | 68881 | 403 | 1 | 129.99 | 129.99 | 
| 172194 | 172195 | 68882 | 365 | 1 | 59.99 | 59.99 | 
| 172195 | 172196 | 68882 | 502 | 1 | 50.00 | 50.00 | 
| 172196 | 172197 | 68883 | 208 | 1 | 1999.99 | 1999.99 | 
| 172197 | 172198 | 68883 | 502 | 3 | 150.00 | 50.00 | 
172198 rows × 6 columns
- Join orders and order_items using orders.order_id and order_items.order_item_order_id. 
orders.join?
Signature: orders.join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False) -> 'DataFrame'
Docstring:
Join columns of another DataFrame.
Join columns with `other` DataFrame either on index or on a key
column. Efficiently join multiple DataFrame objects by index at once by
passing a list.
Parameters
----------
other : DataFrame, Series, or list of DataFrame
    Index should be similar to one of the columns in this one. If a
    Series is passed, its name attribute must be set, and that will be
    used as the column name in the resulting joined DataFrame.
on : str, list of str, or array-like, optional
    Column or index level name(s) in the caller to join on the index
    in `other`, otherwise joins index-on-index. If multiple
    values given, the `other` DataFrame must have a MultiIndex. Can
    pass an array as the join key if it is not already contained in
    the calling DataFrame. Like an Excel VLOOKUP operation.
how : {'left', 'right', 'outer', 'inner'}, default 'left'
    How to handle the operation of the two objects.
    * left: use calling frame's index (or column if on is specified)
    * right: use `other`'s index.
    * outer: form union of calling frame's index (or column if on is
      specified) with `other`'s index, and sort it.
      lexicographically.
    * inner: form intersection of calling frame's index (or column if
      on is specified) with `other`'s index, preserving the order
      of the calling's one.
lsuffix : str, default ''
    Suffix to use from left frame's overlapping columns.
rsuffix : str, default ''
    Suffix to use from right frame's overlapping columns.
sort : bool, default False
    Order result DataFrame lexicographically by the join key. If False,
    the order of the join key depends on the join type (how keyword).
Returns
-------
DataFrame
    A dataframe containing columns from both the caller and `other`.
See Also
--------
DataFrame.merge : For column(s)-on-columns(s) operations.
Notes
-----
Parameters `on`, `lsuffix`, and `rsuffix` are not supported when
passing a list of `DataFrame` objects.
Support for specifying index levels as the `on` parameter was added
in version 0.23.0.
Examples
--------
>>> df = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'],
...                    'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']})
>>> df
  key   A
0  K0  A0
1  K1  A1
2  K2  A2
3  K3  A3
4  K4  A4
5  K5  A5
>>> other = pd.DataFrame({'key': ['K0', 'K1', 'K2'],
...                       'B': ['B0', 'B1', 'B2']})
>>> other
  key   B
0  K0  B0
1  K1  B1
2  K2  B2
Join DataFrames using their indexes.
>>> df.join(other, lsuffix='_caller', rsuffix='_other')
  key_caller   A key_other    B
0         K0  A0        K0   B0
1         K1  A1        K1   B1
2         K2  A2        K2   B2
3         K3  A3       NaN  NaN
4         K4  A4       NaN  NaN
5         K5  A5       NaN  NaN
If we want to join using the key columns, we need to set key to be
the index in both `df` and `other`. The joined DataFrame will have
key as its index.
>>> df.set_index('key').join(other.set_index('key'))
      A    B
key
K0   A0   B0
K1   A1   B1
K2   A2   B2
K3   A3  NaN
K4   A4  NaN
K5   A5  NaN
Another option to join using the key columns is to use the `on`
parameter. DataFrame.join always uses `other`'s index but we can use
any column in `df`. This method preserves the original DataFrame's
index in the result.
>>> df.join(other.set_index('key'), on='key')
  key   A    B
0  K0  A0   B0
1  K1  A1   B1
2  K2  A2   B2
3  K3  A3  NaN
4  K4  A4  NaN
5  K5  A5  NaN
File:      /opt/anaconda3/envs/beakerx/lib/python3.6/site-packages/pandas/core/frame.py
Type:      method
orders.set_index('order_id')
| order_date | order_customer_id | order_status | |
|---|---|---|---|
| order_id | |||
| 1 | 2013-07-25 00:00:00.0 | 11599 | CLOSED | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 
| 3 | 2013-07-25 00:00:00.0 | 12111 | COMPLETE | 
| 4 | 2013-07-25 00:00:00.0 | 8827 | CLOSED | 
| 5 | 2013-07-25 00:00:00.0 | 11318 | COMPLETE | 
| ... | ... | ... | ... | 
| 68879 | 2014-07-09 00:00:00.0 | 778 | COMPLETE | 
| 68880 | 2014-07-13 00:00:00.0 | 1117 | COMPLETE | 
| 68881 | 2014-07-19 00:00:00.0 | 2518 | PENDING_PAYMENT | 
| 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 
| 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 
68883 rows × 3 columns
order_items.set_index('order_item_order_id')
| order_item_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|
| order_item_order_id | |||||
| 1 | 1 | 957 | 1 | 299.98 | 299.98 | 
| 2 | 2 | 1073 | 1 | 199.99 | 199.99 | 
| 2 | 3 | 502 | 5 | 250.00 | 50.00 | 
| 2 | 4 | 403 | 1 | 129.99 | 129.99 | 
| 4 | 5 | 897 | 2 | 49.98 | 24.99 | 
| ... | ... | ... | ... | ... | ... | 
| 68881 | 172194 | 403 | 1 | 129.99 | 129.99 | 
| 68882 | 172195 | 365 | 1 | 59.99 | 59.99 | 
| 68882 | 172196 | 502 | 1 | 50.00 | 50.00 | 
| 68883 | 172197 | 208 | 1 | 1999.99 | 1999.99 | 
| 68883 | 172198 | 502 | 3 | 150.00 | 50.00 | 
172198 rows × 5 columns
# Join orders and order_items using order_id (order_item_order_id from order_items)
orders.set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'))
| order_date | order_customer_id | order_status | order_item_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|---|---|---|
| 1 | 2013-07-25 00:00:00.0 | 11599 | CLOSED | 1.0 | 957.0 | 1.0 | 299.98 | 299.98 | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 2.0 | 1073.0 | 1.0 | 199.99 | 199.99 | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 3.0 | 502.0 | 5.0 | 250.00 | 50.00 | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 4.0 | 403.0 | 1.0 | 129.99 | 129.99 | 
| 3 | 2013-07-25 00:00:00.0 | 12111 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 68881 | 2014-07-19 00:00:00.0 | 2518 | PENDING_PAYMENT | 172194.0 | 403.0 | 1.0 | 129.99 | 129.99 | 
| 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172195.0 | 365.0 | 1.0 | 59.99 | 59.99 | 
| 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172196.0 | 502.0 | 1.0 | 50.00 | 50.00 | 
| 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172197.0 | 208.0 | 1.0 | 1999.99 | 1999.99 | 
| 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172198.0 | 502.0 | 3.0 | 150.00 | 50.00 | 
183650 rows × 8 columns
orders.set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'), how='inner')
| order_date | order_customer_id | order_status | order_item_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|---|---|---|
| 1 | 2013-07-25 00:00:00.0 | 11599 | CLOSED | 1 | 957 | 1 | 299.98 | 299.98 | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 2 | 1073 | 1 | 199.99 | 199.99 | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 3 | 502 | 5 | 250.00 | 50.00 | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 4 | 403 | 1 | 129.99 | 129.99 | 
| 4 | 2013-07-25 00:00:00.0 | 8827 | CLOSED | 5 | 897 | 2 | 49.98 | 24.99 | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 68881 | 2014-07-19 00:00:00.0 | 2518 | PENDING_PAYMENT | 172194 | 403 | 1 | 129.99 | 129.99 | 
| 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172195 | 365 | 1 | 59.99 | 59.99 | 
| 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172196 | 502 | 1 | 50.00 | 50.00 | 
| 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172197 | 208 | 1 | 1999.99 | 1999.99 | 
| 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172198 | 502 | 3 | 150.00 | 50.00 | 
172198 rows × 8 columns
orders.set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'), how='inner'). \
    reset_index()
| index | order_date | order_customer_id | order_status | order_item_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2013-07-25 00:00:00.0 | 11599 | CLOSED | 1 | 957 | 1 | 299.98 | 299.98 | 
| 1 | 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 2 | 1073 | 1 | 199.99 | 199.99 | 
| 2 | 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 3 | 502 | 5 | 250.00 | 50.00 | 
| 3 | 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 4 | 403 | 1 | 129.99 | 129.99 | 
| 4 | 4 | 2013-07-25 00:00:00.0 | 8827 | CLOSED | 5 | 897 | 2 | 49.98 | 24.99 | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 172193 | 68881 | 2014-07-19 00:00:00.0 | 2518 | PENDING_PAYMENT | 172194 | 403 | 1 | 129.99 | 129.99 | 
| 172194 | 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172195 | 365 | 1 | 59.99 | 59.99 | 
| 172195 | 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172196 | 502 | 1 | 50.00 | 50.00 | 
| 172196 | 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172197 | 208 | 1 | 1999.99 | 1999.99 | 
| 172197 | 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172198 | 502 | 3 | 150.00 | 50.00 | 
172198 rows × 9 columns
orders.set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'), how='inner'). \
    reset_index(). \
    rename(columns={'index': 'order_id'})
| order_id | order_date | order_customer_id | order_status | order_item_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2013-07-25 00:00:00.0 | 11599 | CLOSED | 1 | 957 | 1 | 299.98 | 299.98 | 
| 1 | 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 2 | 1073 | 1 | 199.99 | 199.99 | 
| 2 | 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 3 | 502 | 5 | 250.00 | 50.00 | 
| 3 | 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 4 | 403 | 1 | 129.99 | 129.99 | 
| 4 | 4 | 2013-07-25 00:00:00.0 | 8827 | CLOSED | 5 | 897 | 2 | 49.98 | 24.99 | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 172193 | 68881 | 2014-07-19 00:00:00.0 | 2518 | PENDING_PAYMENT | 172194 | 403 | 1 | 129.99 | 129.99 | 
| 172194 | 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172195 | 365 | 1 | 59.99 | 59.99 | 
| 172195 | 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172196 | 502 | 1 | 50.00 | 50.00 | 
| 172196 | 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172197 | 208 | 1 | 1999.99 | 1999.99 | 
| 172197 | 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172198 | 502 | 3 | 150.00 | 50.00 | 
172198 rows × 9 columns
Task 1¶
Compute Daily Revenue using orders.order_date and order_items.order_item_order_subtotal considering only COMPLETE and CLOSED orders.
- Here are the steps to join orders and order_items and get daily revenue. - Create Data Frames for both orders and order_items using data in files. 
- Filter for orders which are either in COMPLETE or CLOSED status. 
- Set the join index for both the Data Frames. 
- Join both the Data Frames using - inner.
- Group the join results using order_date and get daily revenue by using - sumon top of order_item_subtotal.
 
orders_considered = orders.query("order_status in ('COMPLETE', 'CLOSED')")
orders_filtered = orders[orders.order_status.isin(["COMPLETE", "CLOSED"])]
orders_considered. \
    set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'), how='inner'). \
    groupby('order_date')['order_item_subtotal']. \
    agg(['sum']). \
    rename(columns={'sum': 'revenue'})
| revenue | |
|---|---|
| order_date | |
| 2013-07-25 00:00:00.0 | 31547.23 | 
| 2013-07-26 00:00:00.0 | 54713.23 | 
| 2013-07-27 00:00:00.0 | 48411.48 | 
| 2013-07-28 00:00:00.0 | 35672.03 | 
| 2013-07-29 00:00:00.0 | 54579.70 | 
| ... | ... | 
| 2014-07-20 00:00:00.0 | 60047.45 | 
| 2014-07-21 00:00:00.0 | 51427.70 | 
| 2014-07-22 00:00:00.0 | 36717.24 | 
| 2014-07-23 00:00:00.0 | 38795.23 | 
| 2014-07-24 00:00:00.0 | 50885.19 | 
364 rows × 1 columns
Task 2¶
Get all the orders for which there are no corresponding order items.
- We can use default join ( - left) to get orders with out corresponding order items.
orders.set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'))
| order_date | order_customer_id | order_status | order_item_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|---|---|---|
| 1 | 2013-07-25 00:00:00.0 | 11599 | CLOSED | 1.0 | 957.0 | 1.0 | 299.98 | 299.98 | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 2.0 | 1073.0 | 1.0 | 199.99 | 199.99 | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 3.0 | 502.0 | 5.0 | 250.00 | 50.00 | 
| 2 | 2013-07-25 00:00:00.0 | 256 | PENDING_PAYMENT | 4.0 | 403.0 | 1.0 | 129.99 | 129.99 | 
| 3 | 2013-07-25 00:00:00.0 | 12111 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 68881 | 2014-07-19 00:00:00.0 | 2518 | PENDING_PAYMENT | 172194.0 | 403.0 | 1.0 | 129.99 | 129.99 | 
| 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172195.0 | 365.0 | 1.0 | 59.99 | 59.99 | 
| 68882 | 2014-07-22 00:00:00.0 | 10000 | ON_HOLD | 172196.0 | 502.0 | 1.0 | 50.00 | 50.00 | 
| 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172197.0 | 208.0 | 1.0 | 1999.99 | 1999.99 | 
| 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172198.0 | 502.0 | 3.0 | 150.00 | 50.00 | 
183650 rows × 8 columns
orders.set_index('order_id'). \
    join(order_items.set_index('order_item_order_id')). \
    query('order_item_id.isna()')
| order_date | order_customer_id | order_status | order_item_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|---|---|---|
| 3 | 2013-07-25 00:00:00.0 | 12111 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 6 | 2013-07-25 00:00:00.0 | 7130 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 22 | 2013-07-25 00:00:00.0 | 333 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 26 | 2013-07-25 00:00:00.0 | 7562 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 32 | 2013-07-25 00:00:00.0 | 3960 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 68867 | 2014-06-23 00:00:00.0 | 869 | CANCELED | NaN | NaN | NaN | NaN | NaN | 
| 68872 | 2014-06-29 00:00:00.0 | 3354 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 68874 | 2014-07-03 00:00:00.0 | 1601 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 68876 | 2014-07-06 00:00:00.0 | 4124 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 68877 | 2014-07-07 00:00:00.0 | 9692 | ON_HOLD | NaN | NaN | NaN | NaN | NaN | 
11452 rows × 8 columns
orders_joined = orders.set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'))
orders_joined[orders_joined['order_item_id'].isna()]
| order_date | order_customer_id | order_status | order_item_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|---|---|---|
| 3 | 2013-07-25 00:00:00.0 | 12111 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 6 | 2013-07-25 00:00:00.0 | 7130 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 22 | 2013-07-25 00:00:00.0 | 333 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 26 | 2013-07-25 00:00:00.0 | 7562 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 32 | 2013-07-25 00:00:00.0 | 3960 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 68867 | 2014-06-23 00:00:00.0 | 869 | CANCELED | NaN | NaN | NaN | NaN | NaN | 
| 68872 | 2014-06-29 00:00:00.0 | 3354 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 68874 | 2014-07-03 00:00:00.0 | 1601 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 68876 | 2014-07-06 00:00:00.0 | 4124 | COMPLETE | NaN | NaN | NaN | NaN | NaN | 
| 68877 | 2014-07-07 00:00:00.0 | 9692 | ON_HOLD | NaN | NaN | NaN | NaN | NaN | 
11452 rows × 8 columns
Task 3¶
Compute Daily Product Revenue using orders.order_date as well as order_items.order_item_product_id and order_items.order_item_order_subtotal considering only COMPLETE and CLOSED orders.
orders_considered = orders.query("order_status in ('COMPLETE', 'CLOSED')")
orders_filtered = orders[orders.order_status.isin(["COMPLETE", "CLOSED"])]
orders_considered. \
    set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'), how='inner')
| order_date | order_customer_id | order_status | order_item_id | order_item_product_id | order_item_quantity | order_item_subtotal | order_item_product_price | |
|---|---|---|---|---|---|---|---|---|
| 1 | 2013-07-25 00:00:00.0 | 11599 | CLOSED | 1 | 957 | 1 | 299.98 | 299.98 | 
| 4 | 2013-07-25 00:00:00.0 | 8827 | CLOSED | 5 | 897 | 2 | 49.98 | 24.99 | 
| 4 | 2013-07-25 00:00:00.0 | 8827 | CLOSED | 6 | 365 | 5 | 299.95 | 59.99 | 
| 4 | 2013-07-25 00:00:00.0 | 8827 | CLOSED | 7 | 502 | 3 | 150.00 | 50.00 | 
| 4 | 2013-07-25 00:00:00.0 | 8827 | CLOSED | 8 | 1014 | 4 | 199.92 | 49.98 | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 68880 | 2014-07-13 00:00:00.0 | 1117 | COMPLETE | 172191 | 1073 | 1 | 199.99 | 199.99 | 
| 68880 | 2014-07-13 00:00:00.0 | 1117 | COMPLETE | 172192 | 1014 | 5 | 249.90 | 49.98 | 
| 68880 | 2014-07-13 00:00:00.0 | 1117 | COMPLETE | 172193 | 1014 | 3 | 149.94 | 49.98 | 
| 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172197 | 208 | 1 | 1999.99 | 1999.99 | 
| 68883 | 2014-07-23 00:00:00.0 | 5533 | COMPLETE | 172198 | 502 | 3 | 150.00 | 50.00 | 
75408 rows × 8 columns
orders_considered. \
    set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'), how='inner'). \
    groupby(['order_date', 'order_item_product_id'])['order_item_subtotal']
<pandas.core.groupby.generic.SeriesGroupBy object at 0x7f6dc89feeb8>
list(orders_considered. \
    set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'), how='inner'). \
    groupby(['order_date', 'order_item_product_id'])['order_item_subtotal'])[:10]
[(('2013-07-25 00:00:00.0', 24),
  57762    319.96
  Name: order_item_subtotal, dtype: float64),
 (('2013-07-25 00:00:00.0', 93),
  17    74.97
  Name: order_item_subtotal, dtype: float64),
 (('2013-07-25 00:00:00.0', 134),
  12    100.0
  Name: order_item_subtotal, dtype: float64),
 (('2013-07-25 00:00:00.0', 191),
  12       499.95
  28       399.96
  28        99.99
  61       399.96
  71       499.95
  101       99.99
  57757    499.95
  57764    499.95
  57768    499.95
  57776     99.99
  57776     99.99
  57779    499.95
  57782    199.98
  57788    199.98
  57788    499.95
  Name: order_item_subtotal, dtype: float64),
 (('2013-07-25 00:00:00.0', 226),
  68691    599.99
  Name: order_item_subtotal, dtype: float64),
 (('2013-07-25 00:00:00.0', 365),
  4        299.95
  5        299.95
  15       179.97
  17       239.96
  18       119.98
  28        59.99
  37        59.99
  45        59.99
  57       179.97
  57       119.98
  61       119.98
  61       119.98
  71       119.98
  91       299.95
  57756     59.99
  57757    119.98
  57779    299.95
  57781    299.95
  57788    239.96
  67416     59.99
  Name: order_item_subtotal, dtype: float64),
 (('2013-07-25 00:00:00.0', 403),
  5        129.99
  18       129.99
  24       129.99
  35       129.99
  57       129.99
  88       129.99
  98       129.99
  57754    129.99
  57756    129.99
  57757    129.99
  57762    129.99
  57762    129.99
  57768    129.99
  57788    129.99
  68691    129.99
  Name: order_item_subtotal, dtype: float64),
 (('2013-07-25 00:00:00.0', 502),
  4        150.0
  12       250.0
  15        50.0
  24        50.0
  24       250.0
  51        50.0
  62        50.0
  67       150.0
  98       100.0
  57757    150.0
  57758     50.0
  57758    100.0
  57764    150.0
  67416    100.0
  Name: order_item_subtotal, dtype: float64),
 (('2013-07-25 00:00:00.0', 572),
  72    119.97
  Name: order_item_subtotal, dtype: float64),
 (('2013-07-25 00:00:00.0', 625),
  57764    199.99
  Name: order_item_subtotal, dtype: float64)]
orders_considered. \
    set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'), how='inner'). \
    groupby(['order_date', 'order_item_product_id'])['order_item_subtotal']. \
    agg(['sum']). \
    rename(columns={'sum': 'revenue'})
| revenue | ||
|---|---|---|
| order_date | order_item_product_id | |
| 2013-07-25 00:00:00.0 | 24 | 319.96 | 
| 93 | 74.97 | |
| 134 | 100.00 | |
| 191 | 5099.49 | |
| 226 | 599.99 | |
| ... | ... | ... | 
| 2014-07-24 00:00:00.0 | 926 | 31.98 | 
| 957 | 5399.64 | |
| 1004 | 10399.48 | |
| 1014 | 3148.74 | |
| 1073 | 4199.79 | 
9120 rows × 1 columns
orders_considered. \
    set_index('order_id'). \
    join(order_items.set_index('order_item_order_id'), how='inner'). \
    groupby(['order_date', 'order_item_product_id'])['order_item_subtotal']. \
    agg(['sum']). \
    rename(columns={'sum': 'revenue'}). \
    reset_index()
| order_date | order_item_product_id | revenue | |
|---|---|---|---|
| 0 | 2013-07-25 00:00:00.0 | 24 | 319.96 | 
| 1 | 2013-07-25 00:00:00.0 | 93 | 74.97 | 
| 2 | 2013-07-25 00:00:00.0 | 134 | 100.00 | 
| 3 | 2013-07-25 00:00:00.0 | 191 | 5099.49 | 
| 4 | 2013-07-25 00:00:00.0 | 226 | 599.99 | 
| ... | ... | ... | ... | 
| 9115 | 2014-07-24 00:00:00.0 | 926 | 31.98 | 
| 9116 | 2014-07-24 00:00:00.0 | 957 | 5399.64 | 
| 9117 | 2014-07-24 00:00:00.0 | 1004 | 10399.48 | 
| 9118 | 2014-07-24 00:00:00.0 | 1014 | 3148.74 | 
| 9119 | 2014-07-24 00:00:00.0 | 1073 | 4199.79 | 
9120 rows × 3 columns