customeranalytics 0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- customeranalytics/__init__.py +319 -0
- customeranalytics/configs.py +480 -0
- customeranalytics/data_storage_configurations/__init__.py +245 -0
- customeranalytics/data_storage_configurations/data_access.py +165 -0
- customeranalytics/data_storage_configurations/data_works_pipeline.py +207 -0
- customeranalytics/data_storage_configurations/es_create_index.py +544 -0
- customeranalytics/data_storage_configurations/logger.py +36 -0
- customeranalytics/data_storage_configurations/query_es.py +157 -0
- customeranalytics/data_storage_configurations/reports.py +684 -0
- customeranalytics/data_storage_configurations/schedule_data_integration.py +355 -0
- customeranalytics/docs/queries.yaml +245 -0
- customeranalytics/docs/web_configs.yaml +2 -0
- customeranalytics/exploratory_analysis/__init__.py +109 -0
- customeranalytics/exploratory_analysis/churn.py +232 -0
- customeranalytics/exploratory_analysis/cohorts.py +535 -0
- customeranalytics/exploratory_analysis/descriptive_statistics.py +470 -0
- customeranalytics/exploratory_analysis/funnels.py +407 -0
- customeranalytics/exploratory_analysis/product_analytics.py +340 -0
- customeranalytics/exploratory_analysis/promotion_analytics.py +299 -0
- customeranalytics/exploratory_analysis/rfm.py +202 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_avg_order_count_per_promo_per_cust.csv +99 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_chart_1_search.csv +2 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_chart_2_search.csv +46 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_chart_3_search.csv +2 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_chart_4_search.csv +2 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_churn.csv +2 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_churn_weekly.csv +10 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_client_feature_predicted.csv +1590 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_client_kpis.csv +7060 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_clvrfm_anomaly.csv +561 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_clvsegments_amount.csv +8 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_customer_journey.csv +18 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_clv.csv +103 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_downloads.csv +68 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_1_to_2.csv +66 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_2_to_3.csv +64 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_3_to_4.csv +55 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_dimension_values.csv +199 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_funnel.csv +36 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_funnel_downloads.csv +68 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_inorganic_ratio.csv +6070 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_orders.csv +57 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_organic_orders.csv +64 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_products_of_sales.csv +12574 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_promotion_discount.csv +64 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_daily_promotion_revenue.csv +6070 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_dcohort_anomaly.csv +6 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_dcohort_anomaly_2.csv +118 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_deliver.csv +47 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_deliver_kpis.csv +2 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_deliver_weekday_hour.csv +25 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_dfunnel_anomaly.csv +118 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_dimension_kpis.csv +199 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_dorders_anomaly.csv +85 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_frequency_clusters.csv +6 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_frequency_recency.csv +3740 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_funnel.csv +25 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_funnel_downloads.csv +25 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_inorganic_ratio.csv +2353 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_orders.csv +25 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_organic_orders.csv +2353 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_inorganic_orders_per_promotion_per_day.csv +6070 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_kpis.csv +2 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_monetary_clusters.csv +6 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_monetary_frequency.csv +3740 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_funnel.csv +5 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_funnel_downloads.csv +5 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_orders.csv +4 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_most_combined_products.csv +11 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_most_ordered_categories.csv +11 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_most_ordered_products.csv +11 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_order_and_payment_amount_differences.csv +91 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_prepare.csv +101 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_prepare_weekday_hour.csv +25 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_product_kpis.csv +201 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_amount_accept.csv +11 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_amount_reject.csv +7 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_orders_accept.csv +11 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_orders_reject.csv +11 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_comparison.csv +91 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_kpis.csv +99 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_number_of_customer.csv +99 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_amount_accept.csv +81 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_amount_reject.csv +11 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_orders_accept.csv +55 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_orders_reject.csv +37 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_purchase_amount_distribution.csv +22 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_recency_clusters.csv +6 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_recency_monetary.csv +3740 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_rfm.csv +2001 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_ride.csv +101 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_ride_weekday_hour.csv +25 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_segmentation.csv +11 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_daily_before_after_amount.csv +10 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_daily_before_after_orders.csv +9 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_monthly_before_after_amount.csv +10 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_monthly_before_after_orders.csv +11 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_weekly_before_after_amount.csv +10 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_weekly_before_after_orders.csv +10 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_user_counts_per_order_seq.csv +47 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_order_per_user.csv +13 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_payment_amount.csv +13 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_session_per_user.csv +13 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_downloads.csv +13 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_1_to_2.csv +13 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_2_to_3.csv +13 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_3_to_4.csv +12 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_funnel.csv +25 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_funnel_downloads.csv +25 -0
- customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_orders.csv +10 -0
- customeranalytics/ml_process/__init__.py +64 -0
- customeranalytics/ml_process/ab_test.py +615 -0
- customeranalytics/ml_process/anomaly_detection.py +456 -0
- customeranalytics/ml_process/clv_prediction.py +301 -0
- customeranalytics/ml_process/customer_segmentation.py +354 -0
- customeranalytics/ml_process/delivery_analytics.py +754 -0
- customeranalytics/utils.py +186 -0
- customeranalytics/web/app/__init__.py +37 -0
- customeranalytics/web/app/base/__init__.py +9 -0
- customeranalytics/web/app/base/forms.py +16 -0
- customeranalytics/web/app/base/models.py +43 -0
- customeranalytics/web/app/base/routes.py +126 -0
- customeranalytics/web/app/base/static/assets/css/app.css +20 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Black.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Black.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-BlackItalic.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-BlackItalic.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Bold.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Bold.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-BoldItalic.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-BoldItalic.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBold.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBold.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBoldItalic.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBoldItalic.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLight-BETA.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLight-BETA.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLightItalic-BETA.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLightItalic-BETA.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Italic.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Italic.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Light-BETA.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Light-BETA.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-LightItalic-BETA.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-LightItalic-BETA.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Medium.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Medium.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-MediumItalic.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-MediumItalic.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Regular.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Regular.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBold.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBold.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBoldItalic.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBoldItalic.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Thin-BETA.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-Thin-BETA.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ThinItalic-BETA.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-ThinItalic-BETA.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-italic.var.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter-upright.var.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/Inter.var.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.eot +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.svg +3570 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.ttf +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.eot +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.svg +801 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.ttf +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.eot +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.svg +5028 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.ttf +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.woff +0 -0
- customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.woff2 +0 -0
- customeranalytics/web/app/base/static/assets/img/avatars/avatar-1.png +0 -0
- customeranalytics/web/app/base/static/assets/img/avatars/avatar-2.png +0 -0
- customeranalytics/web/app/base/static/assets/img/avatars/avatar-3.png +0 -0
- customeranalytics/web/app/base/static/assets/img/avatars/avatar-4.png +0 -0
- customeranalytics/web/app/base/static/assets/img/avatars/avatar-5.png +0 -0
- customeranalytics/web/app/base/static/assets/img/avatars/info.jpeg +0 -0
- customeranalytics/web/app/base/static/assets/img/icons/customanality.png +0 -0
- customeranalytics/web/app/base/static/assets/img/icons/icon-48x48.png +0 -0
- customeranalytics/web/app/base/static/assets/js/app.js +2 -0
- customeranalytics/web/app/base/static/assets/js/app.js.LICENSE +566 -0
- customeranalytics/web/app/base/static/assets/js/app.js.LICENSE.txt +556 -0
- customeranalytics/web/app/base/static/assets/js/modules/bootstrap.js +15 -0
- customeranalytics/web/app/base/static/assets/js/modules/chartjs.js +4 -0
- customeranalytics/web/app/base/static/assets/js/modules/feather.js +8 -0
- customeranalytics/web/app/base/static/assets/js/modules/flatpickr.js +4 -0
- customeranalytics/web/app/base/static/assets/js/modules/moment.js +4 -0
- customeranalytics/web/app/base/static/assets/js/modules/sidebar.js +23 -0
- customeranalytics/web/app/base/static/assets/js/modules/theme.js +16 -0
- customeranalytics/web/app/base/templates/accounts/login.html +81 -0
- customeranalytics/web/app/base/templates/accounts/register.html +80 -0
- customeranalytics/web/app/base/templates/includes/footer.html +28 -0
- customeranalytics/web/app/base/templates/includes/navigation.html +51 -0
- customeranalytics/web/app/base/templates/includes/scripts.html +3 -0
- customeranalytics/web/app/base/templates/includes/sidebar.html +146 -0
- customeranalytics/web/app/base/templates/layouts/base-fullscreen.html +36 -0
- customeranalytics/web/app/base/templates/layouts/base.html +84 -0
- customeranalytics/web/app/base/util.py +30 -0
- customeranalytics/web/app/home/__init__.py +9 -0
- customeranalytics/web/app/home/forms.py +1039 -0
- customeranalytics/web/app/home/models.py +438 -0
- customeranalytics/web/app/home/profiles.py +310 -0
- customeranalytics/web/app/home/routes.py +386 -0
- customeranalytics/web/app/home/search.py +288 -0
- customeranalytics/web/app/home/static/assets/img/avatars/avatar-1.png +0 -0
- customeranalytics/web/app/home/static/assets/img/avatars/avatar-2.png +0 -0
- customeranalytics/web/app/home/static/assets/img/avatars/avatar-3.png +0 -0
- customeranalytics/web/app/home/static/assets/img/avatars/avatar-4.png +0 -0
- customeranalytics/web/app/home/static/assets/img/avatars/avatar-5.png +0 -0
- customeranalytics/web/app/home/static/assets/img/icons/customanality.png +0 -0
- customeranalytics/web/app/home/static/assets/img/icons/icon-48x48.png +0 -0
- customeranalytics/web/app/home/templates/abtest-product.html +280 -0
- customeranalytics/web/app/home/templates/abtest-promotion.html +362 -0
- customeranalytics/web/app/home/templates/abtest-segments.html +298 -0
- customeranalytics/web/app/home/templates/add-data-delivery.html +184 -0
- customeranalytics/web/app/home/templates/add-data-product.html +177 -0
- customeranalytics/web/app/home/templates/add-data-purchase.html +392 -0
- customeranalytics/web/app/home/templates/anomaly.html +261 -0
- customeranalytics/web/app/home/templates/clv.html +211 -0
- customeranalytics/web/app/home/templates/cohorts.html +308 -0
- customeranalytics/web/app/home/templates/customer-segmentation.html +308 -0
- customeranalytics/web/app/home/templates/data-es.html +152 -0
- customeranalytics/web/app/home/templates/data-execute.html +397 -0
- customeranalytics/web/app/home/templates/delivery.html +404 -0
- customeranalytics/web/app/home/templates/funnel-customer.html +240 -0
- customeranalytics/web/app/home/templates/funnel-session.html +236 -0
- customeranalytics/web/app/home/templates/index.html +524 -0
- customeranalytics/web/app/home/templates/index2.html +515 -0
- customeranalytics/web/app/home/templates/page-403.html +46 -0
- customeranalytics/web/app/home/templates/page-404.html +45 -0
- customeranalytics/web/app/home/templates/page-500.html +45 -0
- customeranalytics/web/app/home/templates/pages-blank.html +33 -0
- customeranalytics/web/app/home/templates/pages-sign-in.html +67 -0
- customeranalytics/web/app/home/templates/pages-sign-up.html +61 -0
- customeranalytics/web/app/home/templates/product.html +203 -0
- customeranalytics/web/app/home/templates/profile.html +1009 -0
- customeranalytics/web/app/home/templates/rfm.html +254 -0
- customeranalytics/web/app/home/templates/search.html +167 -0
- customeranalytics/web/app/home/templates/settings.html +205 -0
- customeranalytics/web/app/home/templates/stats-desc.html +230 -0
- customeranalytics/web/app/home/templates/stats-purchase.html +221 -0
- customeranalytics/web/config.py +30 -0
- customeranalytics/web/db.sqlite3 +0 -0
- customeranalytics/web/run.py +30 -0
- customeranalytics-0.1.dist-info/METADATA +1102 -0
- customeranalytics-0.1.dist-info/RECORD +254 -0
- customeranalytics-0.1.dist-info/WHEEL +4 -0
- customeranalytics-0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from numpy import unique
|
|
4
|
+
import sys, os, inspect
|
|
5
|
+
from sqlalchemy import create_engine, MetaData
|
|
6
|
+
from os.path import dirname, join
|
|
7
|
+
from os import listdir
|
|
8
|
+
from math import sqrt
|
|
9
|
+
|
|
10
|
+
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
|
11
|
+
parentdir = os.path.dirname(currentdir)
|
|
12
|
+
sys.path.insert(0, parentdir)
|
|
13
|
+
|
|
14
|
+
from customeranalytics.configs import descriptive_reports, product_analytics, abtest_reports, non_dimensional_reports, \
|
|
15
|
+
clv_prediction_reports, promotion_analytics, delivery_metrics
|
|
16
|
+
from customeranalytics.utils import *
|
|
17
|
+
from customeranalytics.data_storage_configurations.query_es import QueryES
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
engine = create_engine('sqlite://///' + join(abspath_for_sample_data(), "web", 'db.sqlite3'),
|
|
21
|
+
connect_args={'check_same_thread': False})
|
|
22
|
+
metadata = MetaData()
|
|
23
|
+
con = engine.connect()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Reports:
|
|
27
|
+
"""
|
|
28
|
+
There are some overall values that need to check each day for businesses.
|
|
29
|
+
These values are also crucial metrics for the dashboards.
|
|
30
|
+
These reports are collecting from 'reports' index and storing in a temporary folder.
|
|
31
|
+
This folder path is a required field when ElasticSearch connection is created from the user.
|
|
32
|
+
This process will be triggered when data storage process will be scheduled.
|
|
33
|
+
Daily scheduling will be generated latest reports of the data
|
|
34
|
+
Structure of the folder;
|
|
35
|
+
- temporary_folder
|
|
36
|
+
- build_in_reports
|
|
37
|
+
- main
|
|
38
|
+
- weekly_funnel.csv
|
|
39
|
+
- daily_funnel.csv
|
|
40
|
+
....
|
|
41
|
+
- dimension_1
|
|
42
|
+
- weekly_funnel.csv
|
|
43
|
+
- daily_funnel.csv
|
|
44
|
+
....
|
|
45
|
+
- dimension_2
|
|
46
|
+
- weekly_funnel.csv
|
|
47
|
+
- daily_funnel.csv
|
|
48
|
+
....
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
Here are the reports;
|
|
52
|
+
index : main || report : weekly_funnel
|
|
53
|
+
index : main || report : daily_clv
|
|
54
|
+
index : main || report : daily_funnel
|
|
55
|
+
index : main || report : daily_funnel_downloads
|
|
56
|
+
index : main || report : weekly_average_payment_amount
|
|
57
|
+
index : main || report : product_usage_before_after_orders_reject
|
|
58
|
+
index : main || report : recency_clusters
|
|
59
|
+
index : main || report : weekly_cohort_from_2_to_3
|
|
60
|
+
index : main || report : daily_cohort_from_3_to_4
|
|
61
|
+
index : main || report : promotion_comparison
|
|
62
|
+
index : main || report : promotion_usage_before_after_orders_reject
|
|
63
|
+
index : main || report : most_ordered_products
|
|
64
|
+
index : main || report : daily_organic_orders
|
|
65
|
+
index : main || report : monetary_clusters
|
|
66
|
+
index : main || report : frequency_recency
|
|
67
|
+
index : main || report : segments_change_monthly_before_after_amount
|
|
68
|
+
index : main || report : daily_promotion_revenue
|
|
69
|
+
index : main || report : daily_cohort_from_2_to_3
|
|
70
|
+
index : main || report : weekly_cohort_from_3_to_4
|
|
71
|
+
index : main || report : product_usage_before_after_orders_accept
|
|
72
|
+
index : main || report : frequency_clusters
|
|
73
|
+
index : main || report : monthly_orders
|
|
74
|
+
index : main || report : daily_products_of_sales
|
|
75
|
+
index : main || report : hourly_funnel
|
|
76
|
+
index : main || report : weekly_average_order_per_user
|
|
77
|
+
index : main || report : daily_inorganic_ratio
|
|
78
|
+
index : main || report : daily_cohort_downloads
|
|
79
|
+
index : main || report : hourly_inorganic_ratio
|
|
80
|
+
index : main || report : promotion_number_of_customer
|
|
81
|
+
index : main || report : inorganic_orders_per_promotion_per_day
|
|
82
|
+
index : main || report : promotion_usage_before_after_orders_accept
|
|
83
|
+
index : main || report : recency_monetary
|
|
84
|
+
index : main || report : segments_change_monthly_before_after_orders
|
|
85
|
+
index : main || report : customer_journey
|
|
86
|
+
index : main || report : purchase_amount_distribution
|
|
87
|
+
index : main || report : dfunnel_anomaly
|
|
88
|
+
index : main || report : dcohort_anomaly_2
|
|
89
|
+
index : main || report : segments_change_weekly_before_after_orders
|
|
90
|
+
index : main || report : user_counts_per_order_seq
|
|
91
|
+
index : main || report : daily_cohort_from_1_to_2
|
|
92
|
+
index : main || report : hourly_organic_orders
|
|
93
|
+
index : main || report : weekly_cohort_downloads
|
|
94
|
+
index : main || report : hourly_funnel_downloads
|
|
95
|
+
index : main || report : product_usage_before_after_amount_accept
|
|
96
|
+
index : main || report : client_kpis
|
|
97
|
+
index : main || report : dorders_anomaly
|
|
98
|
+
index : main || report : churn
|
|
99
|
+
index : main || report : monthly_funnel_downloads
|
|
100
|
+
index : main || report : most_combined_products
|
|
101
|
+
index : main || report : avg_order_count_per_promo_per_cust
|
|
102
|
+
index : main || report : dcohort_anomaly
|
|
103
|
+
index : main || report : weekly_cohort_from_1_to_2
|
|
104
|
+
index : main || report : segments_change_daily_before_after_orders
|
|
105
|
+
index : main || report : rfm
|
|
106
|
+
index : main || report : promotion_usage_before_after_amount_accept
|
|
107
|
+
index : main || report : monthly_funnel
|
|
108
|
+
index : main || report : kpis
|
|
109
|
+
index : main || report : churn_weekly
|
|
110
|
+
index : main || report : clvsegments_amount
|
|
111
|
+
index : main || report : order_and_payment_amount_differences
|
|
112
|
+
index : main || report : hourly_orders
|
|
113
|
+
index : main || report : clvrfm_anomaly
|
|
114
|
+
index : main || report : weekly_funnel_downloads
|
|
115
|
+
index : main || report : product_usage_before_after_amount_reject
|
|
116
|
+
index : main || report : weekly_average_session_per_user
|
|
117
|
+
index : main || report : daily_promotion_discount
|
|
118
|
+
index : main || report : product_kpis
|
|
119
|
+
index : main || report : segments_change_weekly_before_after_amount
|
|
120
|
+
index : main || report : daily_orders
|
|
121
|
+
index : main || report : weekly_orders
|
|
122
|
+
index : main || report : segmentation
|
|
123
|
+
index : main || report : segments_change_daily_before_after_amount
|
|
124
|
+
index : main || report : most_ordered_categories
|
|
125
|
+
index : main || report : promotion_usage_before_after_amount_reject
|
|
126
|
+
index : main || report : monetary_frequency
|
|
127
|
+
index : main || report : promotion_kpis
|
|
128
|
+
index : main || report : client_feature_predicted
|
|
129
|
+
|
|
130
|
+
There are some reports which still needs manipulation even they have been applied for data manipulation;
|
|
131
|
+
- promotion_comparison
|
|
132
|
+
- order_and_payment_amount_differences
|
|
133
|
+
- promotion_usage_before_after_amount_reject/ _accept
|
|
134
|
+
- promotion_usage_before_after_orders_reject/ _accept
|
|
135
|
+
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
def __init__(self):
|
|
139
|
+
self.es_tag = {}
|
|
140
|
+
self.folder = join(abspath_for_sample_data(), "exploratory_analysis", 'sample_data', '')
|
|
141
|
+
self.sample_report_names = []
|
|
142
|
+
self.get_main_query = lambda x: " time_period == '{0}' and report_name == '{1}' and type == '{2}' ".format(x[0],
|
|
143
|
+
x[1],
|
|
144
|
+
x[2])
|
|
145
|
+
self.descriptive_reports = descriptive_reports
|
|
146
|
+
self.product_analytics = product_analytics
|
|
147
|
+
self.promotion_analytics = promotion_analytics
|
|
148
|
+
self.abtest_reports = abtest_reports
|
|
149
|
+
self.clv_prediction_reports = clv_prediction_reports
|
|
150
|
+
self.unexpected_reports = ["chart_{}_search".format(str(i)) for i in range(1, 5)]
|
|
151
|
+
self.double_reports = {'promotion_usage_before_after_amount': ['promotion_usage_before_after_amount_accept',
|
|
152
|
+
'promotion_usage_before_after_amount_reject',
|
|
153
|
+
'order_and_payment_amount_differences'],
|
|
154
|
+
'promotion_usage_before_after_orders': ['promotion_usage_before_after_orders_accept',
|
|
155
|
+
'promotion_usage_before_after_orders_reject'],
|
|
156
|
+
'product_usage_before_after_amount': ['product_usage_before_after_amount_accept',
|
|
157
|
+
'product_usage_before_after_amount_reject'],
|
|
158
|
+
'product_usage_before_after_orders': ['product_usage_before_after_orders_accept',
|
|
159
|
+
'product_usage_before_after_orders_reject']
|
|
160
|
+
}
|
|
161
|
+
self.index_kpis = ['total_orders', 'total_visitors', 'total_revenue', 'total_discount',
|
|
162
|
+
'since_last_week_orders', 'since_last_week_revenue',
|
|
163
|
+
'since_last_week_total_visitors', 'since_last_week_total_discount']
|
|
164
|
+
self.p_usage_ba_orders = ['promotion_usage_before_after_orders', 'promotion_usage_before_after_amount']
|
|
165
|
+
self.rfm_reports = ['rfm', 'segmentation']
|
|
166
|
+
self.clv_reports = ["clv_prediction", "stats", "segmentation"]
|
|
167
|
+
self.rfm_metrics = {'recency', 'monetary', 'frequency'}
|
|
168
|
+
self.day_folder = str(current_date_to_day())[0:10]
|
|
169
|
+
self.rfm_metrics_reports = ['frequency_recency', 'recency_monetary', 'monetary_frequency',
|
|
170
|
+
'monetary_clusters', 'frequency_clusters', 'recency_clusters']
|
|
171
|
+
self.naming_decision = lambda x: 'no change' if x.split(" ")[1] == 'decrease/increase' else x.split(" ")[1]
|
|
172
|
+
self.naming = lambda x1, x2: "Frequency; {0}, Monetary ; {1}".format(self.naming_decision(x1),
|
|
173
|
+
self.naming_decision(x2))
|
|
174
|
+
self.delivery_metrics = delivery_metrics
|
|
175
|
+
|
|
176
|
+
def connections(self):
|
|
177
|
+
"""
|
|
178
|
+
connections to sqlite db. tables are;
|
|
179
|
+
- schedule_data
|
|
180
|
+
- es_connection
|
|
181
|
+
- data_columns_integration
|
|
182
|
+
"""
|
|
183
|
+
tag, has_dimension = {}, False
|
|
184
|
+
try:
|
|
185
|
+
self.es_tag = pd.read_sql("SELECT * FROM es_connection", con).to_dict('records')[-1]
|
|
186
|
+
dimensions = pd.read_sql("SELECT * FROM data_connection", con).to_dict('records')[0]
|
|
187
|
+
if dimensions['dimension'] not in ['None', None]:
|
|
188
|
+
has_dimension = True
|
|
189
|
+
except Exception as e:
|
|
190
|
+
print(e)
|
|
191
|
+
return has_dimension
|
|
192
|
+
|
|
193
|
+
def collect_dimensions_for_data_works(self, has_dimensions):
|
|
194
|
+
"""
|
|
195
|
+
If there is dimension in the orders Index all reports will be created individually per indexes
|
|
196
|
+
with 'main' which indicates whole data in orders index
|
|
197
|
+
"""
|
|
198
|
+
dimensions = []
|
|
199
|
+
if has_dimensions:
|
|
200
|
+
try:
|
|
201
|
+
qs = QueryES(host=self.es_tag['host'], port=self.es_tag['port'])
|
|
202
|
+
_res = qs.es.search(index='orders', body={"size": 0,
|
|
203
|
+
"aggs": {"langs": {
|
|
204
|
+
"terms": {"field": "dimension.keyword",
|
|
205
|
+
"size": 500}
|
|
206
|
+
}}})
|
|
207
|
+
_res = [r['key'] for r in _res['aggregations']['langs']['buckets']]
|
|
208
|
+
dimensions = unique(_res).tolist()
|
|
209
|
+
except Exception as e:
|
|
210
|
+
print(e)
|
|
211
|
+
if dimensions not in ['None', None] and len(dimensions) != 1:
|
|
212
|
+
return ['main'] + dimensions
|
|
213
|
+
else:
|
|
214
|
+
return ['main']
|
|
215
|
+
else:
|
|
216
|
+
return ['main']
|
|
217
|
+
|
|
218
|
+
def collect_reports(self, port, host, index, query=None):
|
|
219
|
+
"""
|
|
220
|
+
Query reports index with given date
|
|
221
|
+
"""
|
|
222
|
+
query_es = QueryES(host=host, port=port)
|
|
223
|
+
res = []
|
|
224
|
+
|
|
225
|
+
match = {"size": 1000, "from": 0}
|
|
226
|
+
if query is not None:
|
|
227
|
+
date_queries = None if 'end' not in list(query.keys()) else [
|
|
228
|
+
{'range': {'report_date': {'lt': query['end']}}}]
|
|
229
|
+
|
|
230
|
+
boolean_queries = []
|
|
231
|
+
_keys = list(query.keys())
|
|
232
|
+
for _b in ['index', 'report_name']:
|
|
233
|
+
if _b in _keys:
|
|
234
|
+
boolean_queries.append({'term': {_b: query[_b]}})
|
|
235
|
+
try:
|
|
236
|
+
boolean_queries = None if len(boolean_queries) == 0 else boolean_queries
|
|
237
|
+
query_es.query_builder(boolean_queries=boolean_queries,
|
|
238
|
+
date_queries=date_queries,
|
|
239
|
+
fields=None,
|
|
240
|
+
_source=True)
|
|
241
|
+
match = query_es.match
|
|
242
|
+
except Exception as e:
|
|
243
|
+
print(e)
|
|
244
|
+
|
|
245
|
+
for r in query_es.es.search(index='reports', body=match)['hits']['hits']:
|
|
246
|
+
if r['_source']['index'] == index:
|
|
247
|
+
try:
|
|
248
|
+
_obj = {'report_name': r['_source']['report_name'],
|
|
249
|
+
'report_date': r['_source']['report_date'],
|
|
250
|
+
'time_period': r['_source']['report_types'].get('time_period', None),
|
|
251
|
+
'type': r['_source']['report_types'].get('type', None),
|
|
252
|
+
'_from': r['_source']['report_types'].get('from', None),
|
|
253
|
+
'_to': r['_source']['report_types'].get('to', None),
|
|
254
|
+
'partition': r['_source']['report_types'].get('partition', None),
|
|
255
|
+
'abtest_type': r['_source']['report_types'].get('abtest_type', None),
|
|
256
|
+
'report_types': r['_source']['report_types'],
|
|
257
|
+
'index': r['_source']['index'],
|
|
258
|
+
'data': r['_source']['data']
|
|
259
|
+
}
|
|
260
|
+
res.append(_obj)
|
|
261
|
+
|
|
262
|
+
except Exception as e:
|
|
263
|
+
print(e)
|
|
264
|
+
return pd.DataFrame(res)
|
|
265
|
+
|
|
266
|
+
def split_report_name(self, r_name):
|
|
267
|
+
"""
|
|
268
|
+
get related data from reports index for the given report name
|
|
269
|
+
"""
|
|
270
|
+
_splits = r_name.split("_")
|
|
271
|
+
query = ''
|
|
272
|
+
if 'funnel' in _splits:
|
|
273
|
+
query = self.get_main_query((_splits[0], _splits[1], _splits[2] if len(_splits) == 3 else 'orders'))
|
|
274
|
+
|
|
275
|
+
if 'cohort' in _splits:
|
|
276
|
+
query = self.get_main_query((_splits[0], _splits[1], 'downloads' if _splits[-1] == 'downloads' else 'orders'))
|
|
277
|
+
if 'from' in _splits:
|
|
278
|
+
query += " and _from == '{}' and _to == '{}' ".format(_splits[3], _splits[5])
|
|
279
|
+
if r_name in self.descriptive_reports:
|
|
280
|
+
query = " report_name == 'stats' and type == '{}'".format(r_name)
|
|
281
|
+
if r_name in self.product_analytics:
|
|
282
|
+
query = " report_name == 'product_analytic' and type == '{}'".format(r_name)
|
|
283
|
+
if r_name in self.promotion_analytics:
|
|
284
|
+
query = " report_name == 'promotion_analytic' and type == '{}'".format(r_name)
|
|
285
|
+
if r_name in 'segmentation':
|
|
286
|
+
query = " report_name == 'segmentation'"
|
|
287
|
+
if r_name in 'customer_journey':
|
|
288
|
+
query = " report_name == 'cohort' and type == 'customers_journey'"
|
|
289
|
+
if r_name in 'kpis':
|
|
290
|
+
query = " report_name == 'stats' and type == ''"
|
|
291
|
+
if r_name in 'rfm' or len(set(_splits) & self.rfm_metrics) != 0:
|
|
292
|
+
query = " report_name in ('rfm', 'segmentation')"
|
|
293
|
+
|
|
294
|
+
# ab-test reports
|
|
295
|
+
if r_name == 'promotion_comparison':
|
|
296
|
+
query = " report_name == 'abtest' and abtest_type == 'promotion_comparison'"
|
|
297
|
+
if r_name == 'order_and_payment_amount_differences':
|
|
298
|
+
query = " report_name == 'abtest' and abtest_type in ('{}')".format("', '".join(self.p_usage_ba_orders))
|
|
299
|
+
if r_name in abtest_reports and r_name not in ['promotion_comparison', 'order_and_payment_amount_differences']:
|
|
300
|
+
query = " report_name == 'abtest' and abtest_type == '{}'".format(r_name)
|
|
301
|
+
if 'usage' in _splits:
|
|
302
|
+
for sub_reports in self.double_reports:
|
|
303
|
+
if r_name in self.double_reports[sub_reports]:
|
|
304
|
+
query = " report_name == 'abtest' and abtest_type == '{}'".format(sub_reports)
|
|
305
|
+
|
|
306
|
+
if r_name == 'user_counts_per_order_seq':
|
|
307
|
+
query = " report_name == 'stats' and type == 'user_counts_per_order_seq' "
|
|
308
|
+
if r_name in self.clv_prediction_reports:
|
|
309
|
+
query = "report_name in ( 'clv_prediction', "
|
|
310
|
+
if r_name == 'daily_clv':
|
|
311
|
+
query += " 'stats') and type != type or type == 'daily_revenue' "
|
|
312
|
+
if r_name == 'clvsegments_amount':
|
|
313
|
+
query += " 'segmentation') and type != type "
|
|
314
|
+
if 'anomaly' in r_name.split("_"):
|
|
315
|
+
if r_name in ['dcohort_anomaly', 'dcohort_anomaly_2']:
|
|
316
|
+
_type = 'cohort_d'
|
|
317
|
+
if r_name == 'dfunnel_anomaly':
|
|
318
|
+
_type = 'daily_funnel'
|
|
319
|
+
if r_name == 'dorders_anomaly':
|
|
320
|
+
_type = 'daily_orders_comparison'
|
|
321
|
+
if r_name == 'clvrfm_anomaly':
|
|
322
|
+
_type = 'clv_prediction'
|
|
323
|
+
query = " report_name == 'anomaly' and type == '{}' ".format(_type)
|
|
324
|
+
if 'churn' in r_name.split("_"):
|
|
325
|
+
_type = 'overall'
|
|
326
|
+
_time_period = list({'weekly', 'monthly'} & set(r_name.split("_")))
|
|
327
|
+
_type = _time_period[0] if len(_time_period) != 0 else _type
|
|
328
|
+
query = " report_name == 'churn' and type == '{}' ".format(_type)
|
|
329
|
+
if r_name == 'client_kpis':
|
|
330
|
+
query = "report_name in ('stats', 'rfm')"
|
|
331
|
+
if r_name == 'client_feature_predicted':
|
|
332
|
+
query = "report_name == 'clv_prediction' "
|
|
333
|
+
if r_name == 'dimension_kpis':
|
|
334
|
+
query = "report_name == 'stats' and type == 'dimension_kpis'"
|
|
335
|
+
if r_name == 'daily_dimension_values':
|
|
336
|
+
query = "report_name == 'stats' and type == 'daily_dimension_values'"
|
|
337
|
+
if len(self.delivery_metrics & set(_splits)) != 0:
|
|
338
|
+
query = "report_name == 'delivery_anomaly' and type == '{}'".format(r_name)
|
|
339
|
+
return query
|
|
340
|
+
|
|
341
|
+
def get_promotion_comparison(self, x):
|
|
342
|
+
"""
|
|
343
|
+
This is only for promotion_comparison reports. Promotion fields is stored in the index promo1_promo_2.
|
|
344
|
+
"""
|
|
345
|
+
_x = x.split("_")
|
|
346
|
+
return pd.Series(["_".join(_x[0:2]), "_".join(_x[2:4])])
|
|
347
|
+
|
|
348
|
+
def required_aggregation(self, r_name, data):
|
|
349
|
+
"""
|
|
350
|
+
These is the last data manipulation before stored in the directory.
|
|
351
|
+
"""
|
|
352
|
+
if r_name == 'segmentation':
|
|
353
|
+
total_clients = len(data)
|
|
354
|
+
data = data.groupby("segments").agg({"client": "count"}).reset_index().rename(columns={"client": "value"})
|
|
355
|
+
data['value'] = round((data['value'] * 100) / total_clients, 2)
|
|
356
|
+
if r_name in self.abtest_reports:
|
|
357
|
+
data['diff'] = data['mean_validation'] - data['mean_control']
|
|
358
|
+
if 'usage' in r_name.split("_"):
|
|
359
|
+
accept = 'True' if 'accept' in r_name.split("_") else 'False'
|
|
360
|
+
metric = 'amount' if 'amount' in r_name.split("_") else 'orders'
|
|
361
|
+
data = data.query("is_" + metric + "_increased_per_promotions == " + accept)
|
|
362
|
+
data = data.sort_values('diff') if 'accept' in r_name.split("_") else data
|
|
363
|
+
if r_name == 'promotion_comparison':
|
|
364
|
+
data[['1st promo', '2nd Promo']] = data['promotion_comparison'].apply(
|
|
365
|
+
lambda x: self.get_promotion_comparison(x))
|
|
366
|
+
data['total_effects'] = data['promo_1st_vs_promo_2nd'].apply(
|
|
367
|
+
lambda x: 1 if x in ['True', True] else 0)
|
|
368
|
+
data = data.groupby("1st promo").agg({"total_effects": "sum",
|
|
369
|
+
"accept_Ratio": "mean",
|
|
370
|
+
"promo_1st_vs_promo_2nd": "count"}).reset_index()
|
|
371
|
+
data = data.sort_values(['total_effects'], ascending=False).sort_values(['accept_Ratio'], ascending=True)
|
|
372
|
+
data = data.rename(columns={"promo_1st_vs_promo_2nd": "total_negative_effects"})
|
|
373
|
+
data['total_negative_effects'] = data['total_negative_effects'] - data['total_effects']
|
|
374
|
+
if 'most' in r_name.split("_"):
|
|
375
|
+
if r_name == 'most_combined_products':
|
|
376
|
+
data = data.rename(columns={"product_pair": "products", "total_pairs": "order_count"})
|
|
377
|
+
data = data.sort_values(by='order_count', ascending=False).iloc[:20].reset_index(drop=True)
|
|
378
|
+
return data
|
|
379
|
+
|
|
380
|
+
def get_order_and_payment_amount_differences(self, reports):
|
|
381
|
+
"""
|
|
382
|
+
It is only for 'order_and_payment_amount_differences'. It is the combination of data
|
|
383
|
+
which are 'promotion_usage_before_after_orders' and 'promotion_usage_before_after_amount'.
|
|
384
|
+
"""
|
|
385
|
+
usage_orders = self.required_aggregation(
|
|
386
|
+
r_name=self.p_usage_ba_orders[0], data=pd.DataFrame(list(reports.query("abtest_type == '{}'".format(
|
|
387
|
+
self.p_usage_ba_orders[0]))['data'])[0]))
|
|
388
|
+
usage_amount = self.required_aggregation(
|
|
389
|
+
r_name=self.p_usage_ba_orders[1], data=pd.DataFrame(list(reports.query("abtest_type == '{}'".format(
|
|
390
|
+
self.p_usage_ba_orders[1]))['data'])[0]))
|
|
391
|
+
return pd.merge(usage_orders,
|
|
392
|
+
usage_amount.rename(columns={'diff': 'diff_amount'}),
|
|
393
|
+
on='promotions', how='inner')[['diff_amount', 'diff', 'promotions']]
|
|
394
|
+
|
|
395
|
+
def get_clv_report(self, reports, r_name, index):
|
|
396
|
+
clv_reports = reports.query("report_name == '{}' and type != type".format(self.clv_reports[0]))
|
|
397
|
+
clv_partitions = list(set(clv_reports['partition'].unique()) - {None})
|
|
398
|
+
if len(clv_partitions) == 0:
|
|
399
|
+
clv = pd.DataFrame(list(reports.query("report_name == '{}' and type != type".format(
|
|
400
|
+
self.clv_reports[0]))['data'])[0])
|
|
401
|
+
else:
|
|
402
|
+
clv = pd.DataFrame()
|
|
403
|
+
for i in clv_partitions:
|
|
404
|
+
clv = pd.concat([clv, pd.DataFrame(list(clv_reports.query("partition == @i")['data'])[0])])
|
|
405
|
+
if index != 'main':
|
|
406
|
+
clv = clv.query("dimension == @index")
|
|
407
|
+
if r_name == 'daily_clv':
|
|
408
|
+
daily_revenue = pd.DataFrame(list(reports.query("report_name == '{}' and type == 'daily_revenue'".format(
|
|
409
|
+
self.clv_reports[1]))['data'])[0]).rename(columns={"daily": "date"})
|
|
410
|
+
clv['data_type'] = 'prediction'
|
|
411
|
+
daily_revenue['data_type'] = "actual"
|
|
412
|
+
reports = pd.concat([clv, daily_revenue])[['date', 'payment_amount', 'data_type']]
|
|
413
|
+
reports = reports.groupby(['date', 'data_type']).agg({'payment_amount': 'sum'}).reset_index()
|
|
414
|
+
if r_name == 'clvsegments_amount':
|
|
415
|
+
segments = pd.DataFrame(list(reports.query("report_name == '{}'".format(self.clv_reports[2]))['data'])[0])
|
|
416
|
+
reports = pd.merge(clv, segments, on='client', how='left').groupby("segments").agg(
|
|
417
|
+
{"payment_amount": "sum"}).reset_index()
|
|
418
|
+
return reports
|
|
419
|
+
|
|
420
|
+
def radomly_sample_data(self, data):
|
|
421
|
+
if len(data) > 500:
|
|
422
|
+
data = data.sample(n=500, replace=False)
|
|
423
|
+
return data
|
|
424
|
+
|
|
425
|
+
def get_rfm_reports(self, reports, metrics=[]):
|
|
426
|
+
rfm = pd.DataFrame(list(reports.query("report_name == '{}'".format(self.rfm_reports[0]))['data'])[0])
|
|
427
|
+
segmentation = pd.DataFrame(list(reports.query("report_name == '{}'".format(self.rfm_reports[1]))['data'])[0])
|
|
428
|
+
report = pd.merge(rfm, segmentation, on='client', how='left')
|
|
429
|
+
if len(metrics) != 0:
|
|
430
|
+
if 'clusters' not in metrics:
|
|
431
|
+
report = report[metrics + ['segments_numeric']]
|
|
432
|
+
else:
|
|
433
|
+
_metric = list(set(metrics) & self.rfm_metrics)[0]
|
|
434
|
+
report = report.groupby([_metric + '_segment', _metric]).agg(
|
|
435
|
+
{"client": lambda x: len(np.unique(x))}).reset_index().rename(columns={"client": "client_count"})
|
|
436
|
+
return report
|
|
437
|
+
|
|
438
|
+
def naming(self, metric):
|
|
439
|
+
if metric == 'nomal decrease/increase':
|
|
440
|
+
return 'no change'
|
|
441
|
+
if metric == 'significant decrease':
|
|
442
|
+
return 'decrease'
|
|
443
|
+
if metric == 'significant increase':
|
|
444
|
+
return 'increase'
|
|
445
|
+
|
|
446
|
+
def get_anomaly_reports(self, r_name, report):
|
|
447
|
+
report_data = pd.DataFrame(list(report['data'])[0])
|
|
448
|
+
if r_name == 'dfunnel_anomaly':
|
|
449
|
+
min_as = round(min(report_data['anomaly_scores']) - 0.01, 2)
|
|
450
|
+
max_as = round(max(report_data['anomaly_scores']) + 0.01, 2)
|
|
451
|
+
report_data['outlier'] = report_data['outlier'].apply(lambda x: max_as + 0.01 if x == 1 else min_as - 0.01)
|
|
452
|
+
report_data = report_data.rename(columns={"anomaly_scores":"Anomaly Score Download to First Order"})
|
|
453
|
+
if r_name == 'dcohort_anomaly':
|
|
454
|
+
report_data['daily'] = report_data['daily'].apply(lambda x: convert_to_day(x))
|
|
455
|
+
max_date = str(max(report_data['daily']) - datetime.timedelta(days=30))[0:10]
|
|
456
|
+
report_data = report_data.query("daily > @max_date")
|
|
457
|
+
outlier_days = list(report_data.query("outlier == 1")['daily'])
|
|
458
|
+
_days = list(map(lambda x: str(x)[0:10] + '_outlier' if x in outlier_days else x, list(report_data['daily'])))
|
|
459
|
+
report_data = report_data[[str(i) for i in list(range(0, 5))]].transpose().reset_index()
|
|
460
|
+
report_data.columns = ['days'] + _days
|
|
461
|
+
if r_name == 'dcohort_anomaly_2':
|
|
462
|
+
report_data = report_data[['daily', 'anomaly_scores_from_d_to_1', 'outlier']
|
|
463
|
+
].rename(columns={"anomaly_scores_from_d_to_1": "Anomaly Score Download to First Order"})
|
|
464
|
+
if r_name == 'dorders_anomaly':
|
|
465
|
+
columns = ['diff_perc', 'daily', 'anomalities']
|
|
466
|
+
report_data['anomalities'] = report_data['anomalities'].apply(lambda x: self.naming_decision(x))
|
|
467
|
+
_normal = report_data.query("anomalities == 'no change'")[columns]
|
|
468
|
+
_decrease = report_data.query("anomalities == 'decrease'")[columns]
|
|
469
|
+
_increase = report_data.query("anomalities == 'increase'")[columns]
|
|
470
|
+
report_data = pd.concat([_normal, _decrease, _increase])
|
|
471
|
+
if r_name == 'clvrfm_anomaly':
|
|
472
|
+
report_data['naming'] = report_data.apply(
|
|
473
|
+
lambda row: self.naming(row['f_anomaly'], row['m_anomaly']), axis=1)
|
|
474
|
+
return report_data
|
|
475
|
+
|
|
476
|
+
def get_sample_report_names(self):
|
|
477
|
+
"""
|
|
478
|
+
Collect all sample reports in sample_data folder
|
|
479
|
+
"""
|
|
480
|
+
for f in listdir(dirname(self.folder)):
|
|
481
|
+
if f.split(".")[1] == 'csv':
|
|
482
|
+
_file = "_".join(f.split(".")[0].split("_")[2:])
|
|
483
|
+
if _file not in self.unexpected_reports:
|
|
484
|
+
self.sample_report_names.append(_file)
|
|
485
|
+
|
|
486
|
+
def calculate_last_week_ratios(self, k1, k2, k3):
|
|
487
|
+
"""
|
|
488
|
+
|
|
489
|
+
"""
|
|
490
|
+
return k1 / (k2 - k3) if k2 - k3 != 0 else 0
|
|
491
|
+
|
|
492
|
+
def get_last_week_kpis(self, report):
|
|
493
|
+
"""
|
|
494
|
+
KPIs at index.html are stored at stats report. However there are reports
|
|
495
|
+
which must be calculated calculated before store in built_in reports
|
|
496
|
+
"""
|
|
497
|
+
report_data = pd.DataFrame(list(report['data'])[0])
|
|
498
|
+
report_data['since_last_week_orders'] = report_data.apply(
|
|
499
|
+
lambda row: self.calculate_last_week_ratios(row['total_orders'],
|
|
500
|
+
row['last_week_orders'],
|
|
501
|
+
row['last_week_revenue']), axis=1)
|
|
502
|
+
report_data['since_last_week_revenue'] = report_data.apply(
|
|
503
|
+
lambda row: self.calculate_last_week_ratios(row['last_week_revenue'],
|
|
504
|
+
row['total_revenue'],
|
|
505
|
+
row['last_week_revenue']), axis=1)
|
|
506
|
+
report_data['since_last_week_total_visitors'] = report_data.apply(
|
|
507
|
+
lambda row: self.calculate_last_week_ratios(row['last_week_visitors'],
|
|
508
|
+
row['total_visitors'],
|
|
509
|
+
row['last_week_visitors']), axis=1)
|
|
510
|
+
report_data['since_last_week_total_discount'] = report_data.apply(
|
|
511
|
+
lambda row: self.calculate_last_week_ratios(row['last_week_discount'],
|
|
512
|
+
row['total_discount'],
|
|
513
|
+
row['last_week_discount']), axis=1)
|
|
514
|
+
return report_data[self.index_kpis]
|
|
515
|
+
|
|
516
|
+
def get_client_kpis(self, report):
|
|
517
|
+
"""
|
|
518
|
+
|
|
519
|
+
"""
|
|
520
|
+
total_order_count_per_customer = pd.DataFrame(list(report.query(
|
|
521
|
+
"report_name == 'stats' and type == 'total_order_count_per_customer'").sort_values(
|
|
522
|
+
'report_date', ascending=False)['data'])[0])
|
|
523
|
+
rfm = pd.DataFrame(list(report.query(
|
|
524
|
+
"report_name == 'rfm'").sort_values(
|
|
525
|
+
'report_date', ascending=False)['data'])[0])[['frequency', 'recency', 'monetary', 'client']]
|
|
526
|
+
report_data = pd.merge(total_order_count_per_customer, rfm, on='client', how='inner')
|
|
527
|
+
return report_data
|
|
528
|
+
|
|
529
|
+
def get_feature_predicted_data_per_customer(self, report):
|
|
530
|
+
report_data = pd.DataFrame(list(report['data'])[0])
|
|
531
|
+
return report_data.query("client != 'newcomers'")
|
|
532
|
+
|
|
533
|
+
def get_related_report(self, reports, r_name, index):
|
|
534
|
+
"""
|
|
535
|
+
Last exit before import data as .csv format
|
|
536
|
+
"""
|
|
537
|
+
report_data = pd.DataFrame()
|
|
538
|
+
report = reports.query(self.split_report_name(r_name))
|
|
539
|
+
if len(report) != 0:
|
|
540
|
+
if r_name == 'order_and_payment_amount_differences':
|
|
541
|
+
report_data = self.get_order_and_payment_amount_differences(report)
|
|
542
|
+
if r_name == 'rfm':
|
|
543
|
+
report_data = self.get_rfm_reports(report)
|
|
544
|
+
if r_name in self.rfm_metrics_reports: # rfm rec. - mon.,
|
|
545
|
+
report_data = self.get_rfm_reports(report, metrics=r_name.split("_"))
|
|
546
|
+
if r_name not in ['order_and_payment_amount_differences', 'rfm', 'daily_clv'] + self.rfm_metrics_reports:
|
|
547
|
+
report_data = self.required_aggregation(r_name, pd.DataFrame(list(report['data'])[0]))
|
|
548
|
+
if r_name in ['daily_clv', "clvsegments_amount"]:
|
|
549
|
+
report_data = self.get_clv_report(reports, r_name, index)
|
|
550
|
+
if 'anomaly' in r_name.split("_") and len(self.delivery_metrics & set(r_name.split("_"))) == 0:
|
|
551
|
+
report_data = self.get_anomaly_reports(r_name, report)
|
|
552
|
+
if r_name in self.product_analytics + self.promotion_analytics:
|
|
553
|
+
report_data = pd.DataFrame(pd.DataFrame(list(report['data'])[0]))
|
|
554
|
+
if r_name == 'kpis':
|
|
555
|
+
report_data = self.get_last_week_kpis(report)
|
|
556
|
+
if r_name == 'client_kpis':
|
|
557
|
+
report_data = self.get_client_kpis(report)
|
|
558
|
+
if r_name == 'client_feature_predicted':
|
|
559
|
+
report_data = self.get_feature_predicted_data_per_customer(report)
|
|
560
|
+
if r_name in ['dimension_kpis', 'daily_dimension_values']:
|
|
561
|
+
report_data = pd.DataFrame(list(report['data'])[0])
|
|
562
|
+
if len(self.delivery_metrics & set(r_name.split("_"))) != 0:
|
|
563
|
+
report_data = self.get_delivery_anomaly_report(reports.query(self.split_report_name(r_name)), r_name)
|
|
564
|
+
|
|
565
|
+
report_data = self.radomly_sample_data(report_data)
|
|
566
|
+
return report_data
|
|
567
|
+
|
|
568
|
+
def get_delivery_anomaly_report(self, reports, r_name):
|
|
569
|
+
report_data = pd.DataFrame(list(reports['data'])[0])
|
|
570
|
+
if 'weekday' in r_name.split("_"):
|
|
571
|
+
report_data = self.get_delivery_anomaly_data(report_data)
|
|
572
|
+
else:
|
|
573
|
+
if r_name != 'deliver_kpis':
|
|
574
|
+
metric = list(self.delivery_metrics & set(r_name.split("_")))[0]
|
|
575
|
+
report_data = self.get_delivery_anomaly_map_report(report_data, metric)
|
|
576
|
+
return report_data
|
|
577
|
+
|
|
578
|
+
def get_delivery_anomaly_data(self, report_data):
|
|
579
|
+
return pd.DataFrame(np.array(report_data.pivot_table(index='hour',
|
|
580
|
+
columns='isoweekday',
|
|
581
|
+
aggfunc={"weekday_hour_norm": 'max'}).reset_index()))
|
|
582
|
+
|
|
583
|
+
def get_delivery_anomaly_map_report(self, report_data, metric):
|
|
584
|
+
_mean, _std, _sample = np.median(report_data[metric]), np.std(report_data[metric]), len(report_data)
|
|
585
|
+
conf_interval_l_tail = max(0, _mean - (sqrt(2.58 * _std) / sqrt(_sample)))
|
|
586
|
+
conf_interval_r_tail = _mean + ((2.58 * _std) / sqrt(_sample))
|
|
587
|
+
report_data = report_data[
|
|
588
|
+
(report_data[metric] > conf_interval_l_tail) & (report_data[metric] < conf_interval_r_tail)]
|
|
589
|
+
report_data = report_data if len(report_data) < 100 else report_data.sample(100)
|
|
590
|
+
return report_data
|
|
591
|
+
|
|
592
|
+
def get_report_count(self, es_tag):
|
|
593
|
+
"""
|
|
594
|
+
Check if the reports are stored in to the reports index.
|
|
595
|
+
"""
|
|
596
|
+
reports_index_count = {}
|
|
597
|
+
try:
|
|
598
|
+
qs = QueryES(host=es_tag['host'], port=es_tag['port'])
|
|
599
|
+
reports_index_count = qs.es.cat.count('reports', params={"format": "json"})
|
|
600
|
+
except Exception as e:
|
|
601
|
+
print(e)
|
|
602
|
+
return reports_index_count
|
|
603
|
+
|
|
604
|
+
def get_import_file_path(self, r_name, index, day_folder=False):
|
|
605
|
+
"""
|
|
606
|
+
importing file path for .csv file to the build_in_reports
|
|
607
|
+
"""
|
|
608
|
+
if not day_folder:
|
|
609
|
+
return join(self.es_tag['directory'], "build_in_reports", index, r_name) + ".csv"
|
|
610
|
+
else:
|
|
611
|
+
return join(self.es_tag['directory'], "build_in_reports", index, self.day_folder, r_name) + ".csv"
|
|
612
|
+
|
|
613
|
+
def collect_non_dimensional_reports(self):
|
|
614
|
+
additional_reports = []
|
|
615
|
+
for r in non_dimensional_reports:
|
|
616
|
+
additional_reports.append(self.collect_reports(port=self.es_tag['port'],
|
|
617
|
+
host=self.es_tag['host'],
|
|
618
|
+
index='main',
|
|
619
|
+
query={"report_name": r}))
|
|
620
|
+
return additional_reports
|
|
621
|
+
|
|
622
|
+
def check_for_folder(self):
|
|
623
|
+
try:
|
|
624
|
+
os.mkdir(join(self.es_tag['directory'], "build_in_reports"))
|
|
625
|
+
except:
|
|
626
|
+
print("folder already exists")
|
|
627
|
+
|
|
628
|
+
def check_for_index_folder(self, index):
|
|
629
|
+
try: os.mkdir(join(self.es_tag['directory'], "build_in_reports", index))
|
|
630
|
+
except: print("folder already exists")
|
|
631
|
+
|
|
632
|
+
def check_for_day_folder(self, index):
|
|
633
|
+
try: os.mkdir(join(self.es_tag['directory'], "build_in_reports", index, self.day_folder))
|
|
634
|
+
except: print("folder already exists")
|
|
635
|
+
|
|
636
|
+
def create_build_in_reports(self):
|
|
637
|
+
"""
|
|
638
|
+
This is the main process of importing data into the given directory in .csv format.
|
|
639
|
+
For each index, separate reports are imported.
|
|
640
|
+
"""
|
|
641
|
+
self.get_sample_report_names()
|
|
642
|
+
has_dimensions = self.connections()
|
|
643
|
+
self.check_for_folder()
|
|
644
|
+
|
|
645
|
+
if len(self.get_report_count(self.es_tag)) != 0:
|
|
646
|
+
dimensions = self.collect_dimensions_for_data_works(has_dimensions)
|
|
647
|
+
|
|
648
|
+
for index in dimensions:
|
|
649
|
+
reports = self.collect_reports(self.es_tag['port'], self.es_tag['host'], index)
|
|
650
|
+
reports = pd.concat([reports] + self.collect_non_dimensional_reports())
|
|
651
|
+
reports['report_date'] = reports['report_date'].apply(lambda x: convert_to_day(x))
|
|
652
|
+
reports = reports.sort_values(['report_name', 'report_date'], ascending=False)
|
|
653
|
+
if len(reports) != 0: # if there has NOT been created any report, yet
|
|
654
|
+
try:
|
|
655
|
+
self.check_for_index_folder(index)
|
|
656
|
+
self.check_for_day_folder(index)
|
|
657
|
+
for r_name in self.sample_report_names:
|
|
658
|
+
print("index :", index, "|| report : ", r_name)
|
|
659
|
+
_data = self.get_related_report(reports, r_name, index)
|
|
660
|
+
if len(_data) != 0:
|
|
661
|
+
_data.to_csv(self.get_import_file_path(r_name, index), index=False)
|
|
662
|
+
_data.to_csv(self.get_import_file_path(r_name, index, day_folder=True), index=False)
|
|
663
|
+
except Exception as e:
|
|
664
|
+
pass
|
|
665
|
+
|
|
666
|
+
def query_es_for_report(self, report_name, index, date=datetime.datetime.now()):
|
|
667
|
+
## TODO: will be updated
|
|
668
|
+
""""
|
|
669
|
+
"""
|
|
670
|
+
query = {'index': index,
|
|
671
|
+
'report_name': report_name,
|
|
672
|
+
'end': convert_to_iso_format(date),
|
|
673
|
+
'start': convert_to_iso_format(convert_to_day(date) - datetime.timedelta(days=1))}
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
|