{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-02T19:21:17.899282Z","iopub.execute_input":"2022-08-02T19:21:17.900562Z","iopub.status.idle":"2022-08-02T19:21:17.935646Z","shell.execute_reply.started":"2022-08-02T19:21:17.900421Z","shell.execute_reply":"2022-08-02T19:21:17.934700Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"text-align:center;font-size:400%;font-family:Times New Roman;\"><b>Introduction</b> <mark>(in progress)</mark></h1>\n\n<br>\n    \n<p>\nThis notebook is my initial investigation for patterns on *customer_ID's* and the *S_2* from the amex-default-prediction (AMP) dataset.\n</p>\n    \n## __Purpose__\n\n##### Some questions I'm hoping to answer are the following...\n\n   ##### 1. What are there patterns in the observations of customer_ID's from 2017 to March 2018?\n   ##### 2. Are there missing statments? \n   ##### 3. Do the statement dates remain the same per customer during the observation period?\n   ##### 4. When do statment dates occur in terms of Min, Max, Monday through Friday, begining / end of the month, et cetera?\n    \n## __Install Requirements__\n\n##### The install requirements for this notebook is Pyspark version 3.3.0 \n","metadata":{}},{"cell_type":"code","source":"!pip install pyspark==3.3.0\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-08-02T21:05:56.240719Z","iopub.execute_input":"2022-08-02T21:05:56.243203Z","iopub.status.idle":"2022-08-02T21:06:08.319259Z","shell.execute_reply.started":"2022-08-02T21:05:56.243154Z","shell.execute_reply":"2022-08-02T21:06:08.317684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## __Load Packages__","metadata":{}},{"cell_type":"code","source":"# Pyspark Pkgs 💾💿💾💿\nfrom pyspark.sql import SparkSession\nfrom pyspark.sql.functions import year, weekofyear, dayofyear, month, dayofmonth, dayofweek\nfrom pyspark.sql.types import StructType,StructField,StringType,DateType,FloatType,IntegerType\nfrom pyspark.sql.functions import date_format\n\n# datframes 📅 and tools 🔧🔨\n# import pandas as pd\nfrom pandas.api.types import CategoricalDtype\n# import numpy as np\nimport calendar\n\n# Vis 🎨\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nsns.set()\n\n# Garbage 🧺 \nimport gc","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:06:08.322191Z","iopub.execute_input":"2022-08-02T21:06:08.322560Z","iopub.status.idle":"2022-08-02T21:06:09.633524Z","shell.execute_reply.started":"2022-08-02T21:06:08.322528Z","shell.execute_reply":"2022-08-02T21:06:09.632446Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":" ## __Custom functions__\n\nThe make_schema function takes a sample from the training path and loads into a pandas data frame. Then returns a pyspark schemea with the dtypes taken from the pandas dataframe. The alpha parameter was set for internal testing, but is not 100% reliable. This function is likely found in many notebooks, but I think allot my inspiration for this function came from [Rakka](https://www.kaggle.com/code/rakkaalhazimi/export-large-dataset-to-spark). Also, included is an abline function that will help create regression lines for some of the data visuliations.    ","metadata":{}},{"cell_type":"code","source":"def make_schema(train_path,alpha=1000):\n    known_string_types = ['customer_ID','B_30', 'B_38', 'D_114', 'D_116', 'D_117', 'D_120', 'D_126', 'D_63', 'D_64', 'D_66', 'D_68']\n    known_date_types = ['S_2']\n    types_map = {\n    \"object\": StringType(),\n    \"float64\": FloatType(),\n    \"int64\": IntegerType(),\n    }\n    df_types = pd.read_csv(train_path, nrows=alpha).dtypes\n    fields = []    \n    for index, value in df_types.items():\n        if index in known_string_types:\n            field = StructField(index, StringType(), True)        \n        elif index in known_date_types:\n            field = StructField(index, DateType(), True)\n        else:\n            field = StructField(index, types_map.get(str(value)), True)            \n        fields.append(field)\n    return StructType(fields)\n\ndef abline(x, y, ax, color, label):\n    slope = np.polyfit(x,y,1)[0]\n    intercept = np.polyfit(x,y,1)[1]\n    x_vals = np.array(ax.get_xlim())\n    y_vals = intercept + slope * x_vals\n    return  ax.plot(x_vals, y_vals, '--', color=color, label=\"Regression Line\")\n\ndef make_plot(plotTypea, col_x, col_y, data, xLabel, yLabel, title, label, abline=False):\n    x = data[col_x].values.tolist()\n    y = data[col_y].values.tolist()    \n    fig, ax = plt.subplots()    \n    line1 = ax.plot(x, y, color='red', label=label)\n    if abline:\n        line2 = abline(x_int, y, ax, color='blue', label=\"Regression Line\")   \n    plt.xlabel(xLabel)\n    plt.ylabel(yLabel)\n    plt.title(title, fontweight='bold')\n    plt.legend(facecolor=\"grey\")\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:06:09.634887Z","iopub.execute_input":"2022-08-02T21:06:09.635686Z","iopub.status.idle":"2022-08-02T21:06:09.650488Z","shell.execute_reply.started":"2022-08-02T21:06:09.635651Z","shell.execute_reply":"2022-08-02T21:06:09.649339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## __Initialize Pyspark Framework and Read Training Data__\n\nIts important to note that this notebook will only read in the features __customer_ID__ & __S_2__. The customer_ID is a discrete nominal variable and will have little interperation outside describing other fetures in temporal sense. The S_2 is a date variable and can be treated either as catorgial and or continuous data type(s). With this date variable, I will build new fetures to leverage view to the temporal patterns in the data.  \n\nBeing some what new to Pyspark, the configurations is still a work in progress. If anyone has good resources for learning these configurations would be very appreciated.","metadata":{}},{"cell_type":"code","source":"train_path = \"../input/amex-default-prediction/train_data.csv\"\nworking_path = \"./\"\n\nspark = SparkSession \\\n    .builder \\\n    .appName(\"Customer_ID_Observations\") \\\n    .config(\"spark.executor.memory\", \"6g\") \\\n    .config(\"spark.driver.memory\", \"4g\")\\\n    .getOrCreate()\n\nspark_df = spark.read.csv(\n    train_path,\n    schema=make_schema(train_path),\n    header=True)\\\n    .select([\"customer_ID\", \"S_2\"])\n\nspark_df = spark_df\\\n    .withColumn(\"year\",year(spark_df.S_2)) \\\n    .withColumn(\"week_of_year\", weekofyear(spark_df.S_2)) \\\n    .withColumn(\"day_of_year\", dayofyear(spark_df.S_2)) \\\n    .withColumn(\"month\", month(spark_df.S_2)) \\\n    .withColumn(\"day_of_month\", dayofmonth(spark_df.S_2)) \\\n    .withColumn(\"day_of_week\", dayofweek(spark_df.S_2)) \\\n    .withColumn(\"day\", date_format('S_2', 'EEEE'))","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:06:09.652615Z","iopub.execute_input":"2022-08-02T21:06:09.653483Z","iopub.status.idle":"2022-08-02T21:06:19.965705Z","shell.execute_reply.started":"2022-08-02T21:06:09.653434Z","shell.execute_reply":"2022-08-02T21:06:19.964008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n<h3 style=\"font-family:Times New Roman;\"><b>Save the Memory and Partition the Data!</b></h3>\n\nBecause the training data is so large, hence my motivation to learn spark, I've learned that partitioning the data can help cut down the memory usage, especially when levergaging multiple nodes with a high amount of CPU cores","metadata":{}},{"cell_type":"code","source":"# Partition the data for better memory use\nspark_df.write.partitionBy('year', 'month').mode(\"overwrite\").parquet(working_path+r\"/year_month_partition_path/\")\nprint(\"Partition Complete\")\n\n# Delete the spark object and take out the trash.  \ndel spark_df\n_ = gc.collect()","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:06:19.970264Z","iopub.execute_input":"2022-08-02T21:06:19.972940Z","iopub.status.idle":"2022-08-02T21:08:09.854396Z","shell.execute_reply.started":"2022-08-02T21:06:19.972881Z","shell.execute_reply":"2022-08-02T21:08:09.852686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n<h2 style=\"text-align:center;font-size:400%;font-family:Times New Roman;\"><b>2017 Observations</b></h2>\n<br>\n<center>\n    <img src=\"https://d3t3ozftmdmh3i.cloudfront.net/production/podcast_uploaded_nologo400/24129232/24129232-1649747946735-ab3f24929ec48.jpg\">\n</center>\n<br>\n<br>\n<br>\n<h4 style=\"font-family:Times New Roman;\"><b>Count Customer Statments by Month:</b><span style=\"color:blue;\"> Initial Observation</span></h4>\n<br>\n<p1>\n<span style=\"font-size:230%;font-family:Times New Roman;\">\nT\n</span>\n<span style=\"font-size:130%;font-family:Times New Roman;\">\nhe first observation is a month-to-month view of the count of Customer Statements (<em>customer_ID</em>'s). This obsevation reveals the total count of customer_ID's being positive and linear from May to Decemcember of 2017. In other words, AMEX attracted allot of customers and or reoccurance of previously observed customers retaining their AMEX CC. Looking at strictly at May the count of customer statments appear to have deviated from its original in April. This deviation of  Customers is unkown at this time, but I suspect its a result of some sort of imbalced count of customers when observed through a lens of time focused by the behavorial and economic fetures to the Amex customer.\n</span>\n</p1>\n<br>\n<br>\n<br>","metadata":{}},{"cell_type":"code","source":"# Read all data 2017 data & Prep for SQL. \nworking_path = r\"./year_month_partition_path/\"\nyear2017 = spark.read.parquet(working_path+r'year=2017/month=*')\nyear2017.createOrReplaceTempView(\"year2017\")\n\nSQL = \"\"\"\nSELECT month_int, month, COUNT(customer_ID) AS customer_ID_COUNT\nFROM(\nSELECT MONTH(S_2) month_int, date_format(year2017.S_2,'MMM') AS month, year2017.customer_ID\nFROM year2017)\nGROUP By 1, 2\nORDER BY 1, 2\n\"\"\"\n\n# Querry the custom SQL to a pandas DF.  \nmonths_2017 = spark.sql(SQL).toPandas()\n\n# Plot the count of monthly statment for 2017\nfig, line = plt.subplots(figsize=(16,6))\nline.set_xlabel(\"Month\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_ylabel(\"Customer ID Counts\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_title('Count Customer Statments by Month',fontdict= { 'fontsize': 20,'fontweight':'bold'})\nline.tick_params(axis='x', labelrotation = 45)\nline = sns.lineplot(data=months_2017, x=\"month\", y=\"customer_ID_COUNT\")\n","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:08:09.856047Z","iopub.execute_input":"2022-08-02T21:08:09.856410Z","iopub.status.idle":"2022-08-02T21:08:16.575869Z","shell.execute_reply.started":"2022-08-02T21:08:09.856378Z","shell.execute_reply":"2022-08-02T21:08:16.574678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p2>\n    <span style=\"font-size:230%;font-family:Times New Roman;\">\n        W</span><span style=\"font-size:130%;font-family:Times New Roman;\">hen obseving the <b>Count Customer Statements by the Month </b>, I've come to the conclusion that it only describes the final monthly customer count being a total count which exceeds, subseeds, or meets the count of customer staments from the previous months observed. For example, looking at April to May on the<b>Count Customer Statements by the Month </b>, April has a starting count that exceeds total count of March. This is logicaly okay, but looking at start of May, the total customer count subseeds the total count in April. This is of mintrest because at first glance, it appears there may be missing customer statments.   \n    </span.\n</p2>\n<br>\n<br>\n<p3>\n<span style=\"font-size:100%;font-family:Times New Roman;\">\nWhen the customer count subseedes the count from the previous monthly count, my intuion leads me to believe that 1 of 3 things have occured.\n <ol>\n  <li>Customers are not missing and can be observed from with a non-monthly distribution of statements</li>\n  <li>Customers are missing because they are no longer an Amex customer</li>\n  <li>Customers are missing because they have a history of defaulting on their CC, causing the total counts to subseede their hiostorical observations. Assuming their is a correlation between the CC holders who default and the months that have subseeding customers </li>\n </ol>\n    </span.\n</pr3> \n<br>\n\n","metadata":{}},{"cell_type":"markdown","source":"<h4 style=\"font-family:Times New Roman;\"><b>Count Only the New Customer Statments by Month:</b><span style=\"color:blue;\"> Initial Observation</span></h4>","metadata":{}},{"cell_type":"code","source":"SQL=\"\"\"\nSELECT f.month,\nCASE\n    WHEN f.month == 3 THEN \"Mar\"\n    WHEN f.month == 4 THEN \"Apr\"\n    WHEN f.month == 5 THEN \"May\"\n    WHEN f.month == 6 THEN \"Jun\"\n    WHEN f.month == 7 THEN \"Jul\"\n    WHEN f.month == 8 THEN \"Aug\"\n    WHEN f.month == 9 THEN \"Sep\"\n    WHEN f.month == 10 THEN \"Oct\"\n    WHEN f.month == 11 THEN \"Nov\"\n    ELSE \"Dec\"\nEND AS month_str, f.new_custmr_cnt\nFROM\n    (SELECT c.month, COUNT(c.month) AS new_custmr_cnt\n    FROM\n        (SELECT customer_ID, min(MONTH(S_2)) AS month\n        FROM year2017\n        GROUP BY 1\n        ORDER BY 2, 1) c\n        GROUP BY 1\n    ORDER BY 1) f\n\"\"\"\n\nfirst_apperance = spark.sql(SQL).toPandas()\n\nfig, line = plt.subplots(figsize=(16,6))\nline.set_xlabel(\"Month\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_ylabel(\"New Customer Counts\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_title('Count Only the New Customer Statments by Month',fontdict= { 'fontsize': 20,'fontweight':'bold'})\nline.tick_params(axis='x', labelrotation = 45)\nline = sns.lineplot(data=first_apperance.loc[1:], x=\"month_str\", y=\"new_custmr_cnt\")","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:08:16.577478Z","iopub.execute_input":"2022-08-02T21:08:16.578513Z","iopub.status.idle":"2022-08-02T21:08:26.173863Z","shell.execute_reply.started":"2022-08-02T21:08:16.578448Z","shell.execute_reply":"2022-08-02T21:08:26.172660Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3 style=\"font-family:Times New Roman;\"><b>Count Customer Statments by the Week Number of Year (00-53):</b><span style=\"color:blue;\"> Initial Observation</span></h3>\n","metadata":{}},{"cell_type":"code","source":"SQL = \"\"\"\nSELECT year2017.week_of_year,COUNT(year2017.customer_ID) AS customer_ID_COUNT\nFROM year2017 \nGROUP By week_of_year\nORDER BY week_of_year\n\"\"\"\n\nweeks_2017 = spark.sql(SQL).toPandas()\n\nx_ticks = list(range(weeks_2017.week_of_year.min(),weeks_2017.week_of_year.max()))\nx_ticks = [num for num in x_ticks if num%2==0]\n\n\nfig, line = plt.subplots(figsize=(16,6))\nline.set_xlabel(\"Week Number\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_ylabel(\"Customer ID Counts\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_title('Count Customer Statments by the Week Number of the Year (00-53)',fontdict= { 'fontsize': 14,'fontweight':'bold'})\nline.tick_params(axis='x', labelrotation = 45)\nline.set_xticks(x_ticks)\nline = sns.lineplot(data=weeks_2017, x=\"week_of_year\", y=\"customer_ID_COUNT\")","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:08:26.177005Z","iopub.execute_input":"2022-08-02T21:08:26.177523Z","iopub.status.idle":"2022-08-02T21:08:29.366594Z","shell.execute_reply.started":"2022-08-02T21:08:26.177476Z","shell.execute_reply":"2022-08-02T21:08:29.365404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p1>\n    <span style=\"font-size:130%;font-family:Times New Roman;\">\n       When observing the count of customer statements by the week, the initial observation should be the wave pattern in the plot. To further investigate this plot I \n       would like to oberseve local extrema and see what those week numbers reveal. In order to capture those points, you need to formualate a function that observes $f(week_{n},week_{n_+1})$  .....  $10\\leq n\\leq 42$.\nThen calculate the derivative, an obeserve the critical points. With the critical points both extrema and minima points (week#) are found. To determine what critical points are the extrema, is to observe tje points each week    \n</p1> ","metadata":{}},{"cell_type":"code","source":"\n\n# Plot the dirivitive\nfig, line = plt.subplots(figsize=(16,6))\ndydx = np.gradient(weeks_2017.customer_ID_COUNT,weeks_2017.week_of_year)\n_=sns.lineplot(data=weeks_2017, x=\"week_of_year\", y=\"customer_ID_COUNT\",label='$y(x)$')\n_=sns.lineplot(x=weeks_2017.week_of_year, y=dydx,label='$y\\'(x)$')\n_=line.legend()\n\n","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:08:38.822664Z","iopub.execute_input":"2022-08-02T21:08:38.823048Z","iopub.status.idle":"2022-08-02T21:08:39.347253Z","shell.execute_reply.started":"2022-08-02T21:08:38.823018Z","shell.execute_reply":"2022-08-02T21:08:39.346121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3 style=\"font-family:Times New Roman;\"><b>Count Customer Statments by the Day Number of Year (000-365):</b><span style=\"color:blue;\"> Initial Observation</span></h3>","metadata":{}},{"cell_type":"code","source":"SQL = \"\"\"\nSELECT\nyear2017.day_of_year, COUNT(year2017.customer_ID) AS customer_ID_COUNT\nFROM year2017 \nGROUP By day_of_year\nORDER BY day_of_year\n\"\"\"\n\nday_2017 = spark.sql(SQL).toPandas()\n\nfig, line = plt.subplots(figsize=(16,6))\nline.set_xlabel(\"Day Number\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_ylabel(\"Customer ID Counts\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_title('Customer Reports by Day: 2017',fontdict= { 'fontsize': 16,'fontweight':'bold'})\nline.tick_params(axis='x', labelrotation = 45)\nline = sns.lineplot(data=day_2017, x=\"day_of_year\", y=\"customer_ID_COUNT\")\n# fig.tight_layout()","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:08:41.432328Z","iopub.execute_input":"2022-08-02T21:08:41.433029Z","iopub.status.idle":"2022-08-02T21:08:44.169183Z","shell.execute_reply.started":"2022-08-02T21:08:41.432986Z","shell.execute_reply":"2022-08-02T21:08:44.168374Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n<h3 style=\"font-family:Times New Roman;\"><b>Count Customer Statments by the Day in a Week:</b><span style=\"color:blue;\"> Initial Observation</span></h3>","metadata":{}},{"cell_type":"code","source":"SQL = \"\"\"\nSELECT day_of_week, day, COUNT(*) as day_counts\nFROM year2017\nGROUP BY day_of_week, day\nORDER BY day_of_week, day\n\"\"\"\n\nday_week2017 = spark.sql(SQL).toPandas()\n\nfig, line = plt.subplots(figsize=(16,6))\nline.set_xlabel(\"Day label\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_ylabel(\"Customer ID Counts\",fontdict= { 'fontsize': 12,'fontweight':'bold'})\nline.set_title('Customer Reports by Day in the week: 2017',fontdict= { 'fontsize': 16,'fontweight':'bold'})\nline.tick_params(axis='x', labelrotation = 45)\nline = sns.lineplot(data=day_week2017, x=\"day\", y=\"day_counts\")\n# # fig.tight_layout()","metadata":{"execution":{"iopub.status.busy":"2022-08-02T21:08:50.753236Z","iopub.execute_input":"2022-08-02T21:08:50.754091Z","iopub.status.idle":"2022-08-02T21:08:53.505670Z","shell.execute_reply.started":"2022-08-02T21:08:50.754043Z","shell.execute_reply":"2022-08-02T21:08:53.504444Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## __Count Customer statments by season__","metadata":{}},{"cell_type":"code","source":"# Seasons Dictionary\nyear2017 = spark.read.parquet(working_path+r'year=2017/month=*')\nseasonal_dict = {\n    \"Winter\":[1,2,12],\n    \"Spring\":[3,4,5],\n    \"Summer\":[6,7,8],\n    \"Autumn\":[9,10,11]\n    }\n\ndef get_season_str(month_int, seasonal_dict=seasonal_dict):\n    result = None\n    if month_int in seasonal_dict[\"Winter\"]:\n        result = \"Winter\"\n    elif month_int in seasonal_dict[\"Autumn\"]:\n        result = \"Autumn\"\n    elif month_int in seasonal_dict[\"Summer\"]:\n        result = \"Summer\"\n    elif month_int in seasonal_dict[\"Spring\"]:\n        result = \"Spring\"\n    else:\n        result = \"Unknown\"\n    return result\n\ncat_season_order = CategoricalDtype(\n    ['Spring', 'Summer', 'Autumn', 'Winter'], \n    ordered=True\n)\n\nSQL = \"\"\"\nSELECT\nMONTH(S_2) AS Month2017, COUNT(DISTINCT year2017.customer_ID) AS COUNT_CustmrID\nFROM year2017 \nGROUP By Month2017\nORDER BY Month2017\n\"\"\"\nmonth2017 = spark.sql(SQL).toPandas()\n\nmonth2017['Month_str'] = month2017['Month2017'].apply(lambda x: calendar.month_abbr[x])\n\nmonth2017['Season'] = month2017['Month2017'].apply(lambda x: get_season_str(month_int=x))\nmonth2017['Season'] = month2017['Season'].astype(cat_season_order)\nmonth2017.groupby('Season')[\"COUNT_CustmrID\"].sum()\n\nseason_tbl = month2017.groupby(['Season'])['COUNT_CustmrID'].sum().to_frame()\nseason_tbl.columns = ['COUNT_CustmrID_Season']\nseason_tbl = season_tbl.reset_index(drop=False)\n\nx = season_tbl[\"Season\"].values.tolist()\ny = season_tbl[\"COUNT_CustmrID_Season\"].values.tolist()\n\nfig, ax = plt.subplots(figsize=(12,7))\nplt.bar(x,y, color='green', label=\"Customer observations\")\nplt.title(\"Customer Counts by season: 2017\",fontweight='bold')\nplt.xlabel(\"Season\")\nplt.ylabel(\"Customer Count\")\nplt.legend(facecolor=\"grey\")\nplt.show()\n\ndel SQL\ndel month2017\ndel season_tbl\ndel x\ndel y\n\n_ = gc.collect()","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-08-02T21:08:55.240119Z","iopub.execute_input":"2022-08-02T21:08:55.241227Z","iopub.status.idle":"2022-08-02T21:09:03.959956Z","shell.execute_reply.started":"2022-08-02T21:08:55.241183Z","shell.execute_reply":"2022-08-02T21:09:03.959016Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## __Customer Reports by day of the week__","metadata":{}},{"cell_type":"code","source":"# Todo","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"spark.stop()","metadata":{},"execution_count":null,"outputs":[]}]}