import pandas as pd
import numpy as np

"""
Explanation: The pivot table is a powerful tool to summarize and present data. Pandas has a function which allows you to quickly convert a DataFrame to a pivot table - 
http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.pivot_table.html
This function is very useful but sometimes it can be tricky to remember how to use it to get the data formatted in a way you need.
This notebook will walk through how to use the pivot_table.
The full blog post for this article is here - http://pbpython.com/pandas-pivot-table-explained.html
Read in the data
End of explanation
"""


df = pd.read_excel("../data/salesfunnel.xlsx")
df.head()

"""
Explanation: Read in our sales funnel data into our DataFrame
End of explanation
"""


df["Status"] = df["Status"].astype("category")
df["Status"].cat.set_categories(["won","pending","presented","declined"],inplace=True)

"""
Explanation: For convenience sake, let's define the status column as a category and set the order we want to view.
This isn't strictly required but helps us keep the order we want as we work through analyzing the data.
End of explanation
"""


pd.pivot_table(df,index=["Name"])

"""
Explanation: Pivot the data
As we build up the pivot table, I think it's easiest to take it one step at a time. Add items one at a time and check each step to verify you are getting the results you expect.
The simplest pivot table must have a dataframe and an index. In this case, let's use the Name as our index.
End of explanation
"""


pd.pivot_table(df,index=["Name","Rep","Manager"])

"""
Explanation: You can have multiple indexes as well. In fact, most of the pivot_table args can take multiple values via a list.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Rep"])

"""
Explanation: This is interesting but not particularly useful. What we probably want to do is look at this by Manager and Director.
It's easy enough to do by changing the index.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Rep"],values=["Price"])

"""
Explanation: You can see that the pivot table is smart enough to start aggregating the data and summarizing it by grouping the reps with their managers. Now we start to get a glimpse of what a pivot table can do for us.
For this purpose, the Account and Quantity columns aren't really useful. Let's remove it by explicitly defining the columns we care about using the values field.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Rep"],values=["Price"],aggfunc=np.sum)

"""
Explanation: The price column automatically averages the data but we can do a count or a sum. Adding them is simple using aggfunc.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Rep"],values=["Price"],aggfunc=[np.mean,len])

"""
Explanation: aggfunc can take a list of functions. Let's try a mean using the numpy functions and len to get a count.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Rep"],values=["Price"],
               columns=["Product"],aggfunc=[np.sum])

"""
Explanation: If we want to see sales broken down by the products, the columns variable allows us to define one or more columns.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Rep"],values=["Price"],
               columns=["Product"],aggfunc=[np.sum],fill_value=0)

"""
Explanation: The NaN's are a bit distracting. If we want to remove them, we could use fill_value to set them to 0.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Rep"],values=["Price","Quantity"],
               columns=["Product"],aggfunc=[np.sum],fill_value=0)

"""
Explanation: I think it would be useful to add the quantity as well. Add Quantity to the values list.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Rep","Product"],
               values=["Price","Quantity"],aggfunc=[np.sum],fill_value=0)

"""
Explanation: What's interesting is that you can move items to the index to get a different visual representation. We can add the Products to the index.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Rep","Product"],
               values=["Price","Quantity"],
               aggfunc=[np.sum,np.mean],fill_value=0,margins=True)

"""
Explanation: For this data set, this representation makes more sense. Now, what if I want to see some totals? margins=True does that for us.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Status"],values=["Price"],
               aggfunc=[np.sum],fill_value=0,margins=True)

"""
Explanation: Let's move the analysis up a level and look at our pipeline at the manager level. Notice how the status is ordered based on our earlier category definition.
End of explanation
"""


pd.pivot_table(df,index=["Manager","Status"],columns=["Product"],values=["Quantity","Price"],
               aggfunc={"Quantity":len,"Price":np.sum},fill_value=0)

"""
Explanation: A really handy feature is the ability to pass a dictionary to the aggfunc so you can perform different functions on each of the values you select. This has a side-effect of making the labels a little cleaner.
End of explanation
"""


table = pd.pivot_table(df,index=["Manager","Status"],columns=["Product"],values=["Quantity","Price"],
               aggfunc={"Quantity":len,"Price":[np.sum,np.mean]},fill_value=0)
table

"""
Explanation: You can provide a list of aggfunctions to apply to each value too:
End of explanation
"""


table.query('Manager == ["Debra Henley"]')

table.query('Status == ["pending","won"]')

"""
Explanation: It can look daunting to try to pull this all together at once but as soon as you start playing with the data and slowly add the items, you can get a feel for how it works.
Advanced Pivot Table Filtering
Once you have generated your data, it is in a DataFrame so you can filter on it using your normal DataFrame functions.
End of explanation
"""


