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.
Files changed (254) hide show
  1. customeranalytics/__init__.py +319 -0
  2. customeranalytics/configs.py +480 -0
  3. customeranalytics/data_storage_configurations/__init__.py +245 -0
  4. customeranalytics/data_storage_configurations/data_access.py +165 -0
  5. customeranalytics/data_storage_configurations/data_works_pipeline.py +207 -0
  6. customeranalytics/data_storage_configurations/es_create_index.py +544 -0
  7. customeranalytics/data_storage_configurations/logger.py +36 -0
  8. customeranalytics/data_storage_configurations/query_es.py +157 -0
  9. customeranalytics/data_storage_configurations/reports.py +684 -0
  10. customeranalytics/data_storage_configurations/schedule_data_integration.py +355 -0
  11. customeranalytics/docs/queries.yaml +245 -0
  12. customeranalytics/docs/web_configs.yaml +2 -0
  13. customeranalytics/exploratory_analysis/__init__.py +109 -0
  14. customeranalytics/exploratory_analysis/churn.py +232 -0
  15. customeranalytics/exploratory_analysis/cohorts.py +535 -0
  16. customeranalytics/exploratory_analysis/descriptive_statistics.py +470 -0
  17. customeranalytics/exploratory_analysis/funnels.py +407 -0
  18. customeranalytics/exploratory_analysis/product_analytics.py +340 -0
  19. customeranalytics/exploratory_analysis/promotion_analytics.py +299 -0
  20. customeranalytics/exploratory_analysis/rfm.py +202 -0
  21. customeranalytics/exploratory_analysis/sample_data/sample_data_avg_order_count_per_promo_per_cust.csv +99 -0
  22. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_1_search.csv +2 -0
  23. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_2_search.csv +46 -0
  24. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_3_search.csv +2 -0
  25. customeranalytics/exploratory_analysis/sample_data/sample_data_chart_4_search.csv +2 -0
  26. customeranalytics/exploratory_analysis/sample_data/sample_data_churn.csv +2 -0
  27. customeranalytics/exploratory_analysis/sample_data/sample_data_churn_weekly.csv +10 -0
  28. customeranalytics/exploratory_analysis/sample_data/sample_data_client_feature_predicted.csv +1590 -0
  29. customeranalytics/exploratory_analysis/sample_data/sample_data_client_kpis.csv +7060 -0
  30. customeranalytics/exploratory_analysis/sample_data/sample_data_clvrfm_anomaly.csv +561 -0
  31. customeranalytics/exploratory_analysis/sample_data/sample_data_clvsegments_amount.csv +8 -0
  32. customeranalytics/exploratory_analysis/sample_data/sample_data_customer_journey.csv +18 -0
  33. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_clv.csv +103 -0
  34. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_downloads.csv +68 -0
  35. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_1_to_2.csv +66 -0
  36. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_2_to_3.csv +64 -0
  37. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_cohort_from_3_to_4.csv +55 -0
  38. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_dimension_values.csv +199 -0
  39. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_funnel.csv +36 -0
  40. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_funnel_downloads.csv +68 -0
  41. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_inorganic_ratio.csv +6070 -0
  42. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_orders.csv +57 -0
  43. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_organic_orders.csv +64 -0
  44. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_products_of_sales.csv +12574 -0
  45. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_promotion_discount.csv +64 -0
  46. customeranalytics/exploratory_analysis/sample_data/sample_data_daily_promotion_revenue.csv +6070 -0
  47. customeranalytics/exploratory_analysis/sample_data/sample_data_dcohort_anomaly.csv +6 -0
  48. customeranalytics/exploratory_analysis/sample_data/sample_data_dcohort_anomaly_2.csv +118 -0
  49. customeranalytics/exploratory_analysis/sample_data/sample_data_deliver.csv +47 -0
  50. customeranalytics/exploratory_analysis/sample_data/sample_data_deliver_kpis.csv +2 -0
  51. customeranalytics/exploratory_analysis/sample_data/sample_data_deliver_weekday_hour.csv +25 -0
  52. customeranalytics/exploratory_analysis/sample_data/sample_data_dfunnel_anomaly.csv +118 -0
  53. customeranalytics/exploratory_analysis/sample_data/sample_data_dimension_kpis.csv +199 -0
  54. customeranalytics/exploratory_analysis/sample_data/sample_data_dorders_anomaly.csv +85 -0
  55. customeranalytics/exploratory_analysis/sample_data/sample_data_frequency_clusters.csv +6 -0
  56. customeranalytics/exploratory_analysis/sample_data/sample_data_frequency_recency.csv +3740 -0
  57. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_funnel.csv +25 -0
  58. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_funnel_downloads.csv +25 -0
  59. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_inorganic_ratio.csv +2353 -0
  60. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_orders.csv +25 -0
  61. customeranalytics/exploratory_analysis/sample_data/sample_data_hourly_organic_orders.csv +2353 -0
  62. customeranalytics/exploratory_analysis/sample_data/sample_data_inorganic_orders_per_promotion_per_day.csv +6070 -0
  63. customeranalytics/exploratory_analysis/sample_data/sample_data_kpis.csv +2 -0
  64. customeranalytics/exploratory_analysis/sample_data/sample_data_monetary_clusters.csv +6 -0
  65. customeranalytics/exploratory_analysis/sample_data/sample_data_monetary_frequency.csv +3740 -0
  66. customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_funnel.csv +5 -0
  67. customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_funnel_downloads.csv +5 -0
  68. customeranalytics/exploratory_analysis/sample_data/sample_data_monthly_orders.csv +4 -0
  69. customeranalytics/exploratory_analysis/sample_data/sample_data_most_combined_products.csv +11 -0
  70. customeranalytics/exploratory_analysis/sample_data/sample_data_most_ordered_categories.csv +11 -0
  71. customeranalytics/exploratory_analysis/sample_data/sample_data_most_ordered_products.csv +11 -0
  72. customeranalytics/exploratory_analysis/sample_data/sample_data_order_and_payment_amount_differences.csv +91 -0
  73. customeranalytics/exploratory_analysis/sample_data/sample_data_prepare.csv +101 -0
  74. customeranalytics/exploratory_analysis/sample_data/sample_data_prepare_weekday_hour.csv +25 -0
  75. customeranalytics/exploratory_analysis/sample_data/sample_data_product_kpis.csv +201 -0
  76. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_amount_accept.csv +11 -0
  77. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_amount_reject.csv +7 -0
  78. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_orders_accept.csv +11 -0
  79. customeranalytics/exploratory_analysis/sample_data/sample_data_product_usage_before_after_orders_reject.csv +11 -0
  80. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_comparison.csv +91 -0
  81. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_kpis.csv +99 -0
  82. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_number_of_customer.csv +99 -0
  83. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_amount_accept.csv +81 -0
  84. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_amount_reject.csv +11 -0
  85. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_orders_accept.csv +55 -0
  86. customeranalytics/exploratory_analysis/sample_data/sample_data_promotion_usage_before_after_orders_reject.csv +37 -0
  87. customeranalytics/exploratory_analysis/sample_data/sample_data_purchase_amount_distribution.csv +22 -0
  88. customeranalytics/exploratory_analysis/sample_data/sample_data_recency_clusters.csv +6 -0
  89. customeranalytics/exploratory_analysis/sample_data/sample_data_recency_monetary.csv +3740 -0
  90. customeranalytics/exploratory_analysis/sample_data/sample_data_rfm.csv +2001 -0
  91. customeranalytics/exploratory_analysis/sample_data/sample_data_ride.csv +101 -0
  92. customeranalytics/exploratory_analysis/sample_data/sample_data_ride_weekday_hour.csv +25 -0
  93. customeranalytics/exploratory_analysis/sample_data/sample_data_segmentation.csv +11 -0
  94. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_daily_before_after_amount.csv +10 -0
  95. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_daily_before_after_orders.csv +9 -0
  96. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_monthly_before_after_amount.csv +10 -0
  97. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_monthly_before_after_orders.csv +11 -0
  98. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_weekly_before_after_amount.csv +10 -0
  99. customeranalytics/exploratory_analysis/sample_data/sample_data_segments_change_weekly_before_after_orders.csv +10 -0
  100. customeranalytics/exploratory_analysis/sample_data/sample_data_user_counts_per_order_seq.csv +47 -0
  101. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_order_per_user.csv +13 -0
  102. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_payment_amount.csv +13 -0
  103. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_average_session_per_user.csv +13 -0
  104. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_downloads.csv +13 -0
  105. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_1_to_2.csv +13 -0
  106. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_2_to_3.csv +13 -0
  107. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_cohort_from_3_to_4.csv +12 -0
  108. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_funnel.csv +25 -0
  109. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_funnel_downloads.csv +25 -0
  110. customeranalytics/exploratory_analysis/sample_data/sample_data_weekly_orders.csv +10 -0
  111. customeranalytics/ml_process/__init__.py +64 -0
  112. customeranalytics/ml_process/ab_test.py +615 -0
  113. customeranalytics/ml_process/anomaly_detection.py +456 -0
  114. customeranalytics/ml_process/clv_prediction.py +301 -0
  115. customeranalytics/ml_process/customer_segmentation.py +354 -0
  116. customeranalytics/ml_process/delivery_analytics.py +754 -0
  117. customeranalytics/utils.py +186 -0
  118. customeranalytics/web/app/__init__.py +37 -0
  119. customeranalytics/web/app/base/__init__.py +9 -0
  120. customeranalytics/web/app/base/forms.py +16 -0
  121. customeranalytics/web/app/base/models.py +43 -0
  122. customeranalytics/web/app/base/routes.py +126 -0
  123. customeranalytics/web/app/base/static/assets/css/app.css +20 -0
  124. customeranalytics/web/app/base/static/assets/fonts/Inter-Black.woff +0 -0
  125. customeranalytics/web/app/base/static/assets/fonts/Inter-Black.woff2 +0 -0
  126. customeranalytics/web/app/base/static/assets/fonts/Inter-BlackItalic.woff +0 -0
  127. customeranalytics/web/app/base/static/assets/fonts/Inter-BlackItalic.woff2 +0 -0
  128. customeranalytics/web/app/base/static/assets/fonts/Inter-Bold.woff +0 -0
  129. customeranalytics/web/app/base/static/assets/fonts/Inter-Bold.woff2 +0 -0
  130. customeranalytics/web/app/base/static/assets/fonts/Inter-BoldItalic.woff +0 -0
  131. customeranalytics/web/app/base/static/assets/fonts/Inter-BoldItalic.woff2 +0 -0
  132. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBold.woff +0 -0
  133. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBold.woff2 +0 -0
  134. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBoldItalic.woff +0 -0
  135. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraBoldItalic.woff2 +0 -0
  136. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLight-BETA.woff +0 -0
  137. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLight-BETA.woff2 +0 -0
  138. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLightItalic-BETA.woff +0 -0
  139. customeranalytics/web/app/base/static/assets/fonts/Inter-ExtraLightItalic-BETA.woff2 +0 -0
  140. customeranalytics/web/app/base/static/assets/fonts/Inter-Italic.woff +0 -0
  141. customeranalytics/web/app/base/static/assets/fonts/Inter-Italic.woff2 +0 -0
  142. customeranalytics/web/app/base/static/assets/fonts/Inter-Light-BETA.woff +0 -0
  143. customeranalytics/web/app/base/static/assets/fonts/Inter-Light-BETA.woff2 +0 -0
  144. customeranalytics/web/app/base/static/assets/fonts/Inter-LightItalic-BETA.woff +0 -0
  145. customeranalytics/web/app/base/static/assets/fonts/Inter-LightItalic-BETA.woff2 +0 -0
  146. customeranalytics/web/app/base/static/assets/fonts/Inter-Medium.woff +0 -0
  147. customeranalytics/web/app/base/static/assets/fonts/Inter-Medium.woff2 +0 -0
  148. customeranalytics/web/app/base/static/assets/fonts/Inter-MediumItalic.woff +0 -0
  149. customeranalytics/web/app/base/static/assets/fonts/Inter-MediumItalic.woff2 +0 -0
  150. customeranalytics/web/app/base/static/assets/fonts/Inter-Regular.woff +0 -0
  151. customeranalytics/web/app/base/static/assets/fonts/Inter-Regular.woff2 +0 -0
  152. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBold.woff +0 -0
  153. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBold.woff2 +0 -0
  154. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBoldItalic.woff +0 -0
  155. customeranalytics/web/app/base/static/assets/fonts/Inter-SemiBoldItalic.woff2 +0 -0
  156. customeranalytics/web/app/base/static/assets/fonts/Inter-Thin-BETA.woff +0 -0
  157. customeranalytics/web/app/base/static/assets/fonts/Inter-Thin-BETA.woff2 +0 -0
  158. customeranalytics/web/app/base/static/assets/fonts/Inter-ThinItalic-BETA.woff +0 -0
  159. customeranalytics/web/app/base/static/assets/fonts/Inter-ThinItalic-BETA.woff2 +0 -0
  160. customeranalytics/web/app/base/static/assets/fonts/Inter-italic.var.woff2 +0 -0
  161. customeranalytics/web/app/base/static/assets/fonts/Inter-upright.var.woff2 +0 -0
  162. customeranalytics/web/app/base/static/assets/fonts/Inter.var.woff2 +0 -0
  163. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.eot +0 -0
  164. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.svg +3570 -0
  165. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.ttf +0 -0
  166. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.woff +0 -0
  167. customeranalytics/web/app/base/static/assets/fonts/fa-brands-400.woff2 +0 -0
  168. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.eot +0 -0
  169. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.svg +801 -0
  170. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.ttf +0 -0
  171. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.woff +0 -0
  172. customeranalytics/web/app/base/static/assets/fonts/fa-regular-400.woff2 +0 -0
  173. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.eot +0 -0
  174. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.svg +5028 -0
  175. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.ttf +0 -0
  176. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.woff +0 -0
  177. customeranalytics/web/app/base/static/assets/fonts/fa-solid-900.woff2 +0 -0
  178. customeranalytics/web/app/base/static/assets/img/avatars/avatar-1.png +0 -0
  179. customeranalytics/web/app/base/static/assets/img/avatars/avatar-2.png +0 -0
  180. customeranalytics/web/app/base/static/assets/img/avatars/avatar-3.png +0 -0
  181. customeranalytics/web/app/base/static/assets/img/avatars/avatar-4.png +0 -0
  182. customeranalytics/web/app/base/static/assets/img/avatars/avatar-5.png +0 -0
  183. customeranalytics/web/app/base/static/assets/img/avatars/info.jpeg +0 -0
  184. customeranalytics/web/app/base/static/assets/img/icons/customanality.png +0 -0
  185. customeranalytics/web/app/base/static/assets/img/icons/icon-48x48.png +0 -0
  186. customeranalytics/web/app/base/static/assets/js/app.js +2 -0
  187. customeranalytics/web/app/base/static/assets/js/app.js.LICENSE +566 -0
  188. customeranalytics/web/app/base/static/assets/js/app.js.LICENSE.txt +556 -0
  189. customeranalytics/web/app/base/static/assets/js/modules/bootstrap.js +15 -0
  190. customeranalytics/web/app/base/static/assets/js/modules/chartjs.js +4 -0
  191. customeranalytics/web/app/base/static/assets/js/modules/feather.js +8 -0
  192. customeranalytics/web/app/base/static/assets/js/modules/flatpickr.js +4 -0
  193. customeranalytics/web/app/base/static/assets/js/modules/moment.js +4 -0
  194. customeranalytics/web/app/base/static/assets/js/modules/sidebar.js +23 -0
  195. customeranalytics/web/app/base/static/assets/js/modules/theme.js +16 -0
  196. customeranalytics/web/app/base/templates/accounts/login.html +81 -0
  197. customeranalytics/web/app/base/templates/accounts/register.html +80 -0
  198. customeranalytics/web/app/base/templates/includes/footer.html +28 -0
  199. customeranalytics/web/app/base/templates/includes/navigation.html +51 -0
  200. customeranalytics/web/app/base/templates/includes/scripts.html +3 -0
  201. customeranalytics/web/app/base/templates/includes/sidebar.html +146 -0
  202. customeranalytics/web/app/base/templates/layouts/base-fullscreen.html +36 -0
  203. customeranalytics/web/app/base/templates/layouts/base.html +84 -0
  204. customeranalytics/web/app/base/util.py +30 -0
  205. customeranalytics/web/app/home/__init__.py +9 -0
  206. customeranalytics/web/app/home/forms.py +1039 -0
  207. customeranalytics/web/app/home/models.py +438 -0
  208. customeranalytics/web/app/home/profiles.py +310 -0
  209. customeranalytics/web/app/home/routes.py +386 -0
  210. customeranalytics/web/app/home/search.py +288 -0
  211. customeranalytics/web/app/home/static/assets/img/avatars/avatar-1.png +0 -0
  212. customeranalytics/web/app/home/static/assets/img/avatars/avatar-2.png +0 -0
  213. customeranalytics/web/app/home/static/assets/img/avatars/avatar-3.png +0 -0
  214. customeranalytics/web/app/home/static/assets/img/avatars/avatar-4.png +0 -0
  215. customeranalytics/web/app/home/static/assets/img/avatars/avatar-5.png +0 -0
  216. customeranalytics/web/app/home/static/assets/img/icons/customanality.png +0 -0
  217. customeranalytics/web/app/home/static/assets/img/icons/icon-48x48.png +0 -0
  218. customeranalytics/web/app/home/templates/abtest-product.html +280 -0
  219. customeranalytics/web/app/home/templates/abtest-promotion.html +362 -0
  220. customeranalytics/web/app/home/templates/abtest-segments.html +298 -0
  221. customeranalytics/web/app/home/templates/add-data-delivery.html +184 -0
  222. customeranalytics/web/app/home/templates/add-data-product.html +177 -0
  223. customeranalytics/web/app/home/templates/add-data-purchase.html +392 -0
  224. customeranalytics/web/app/home/templates/anomaly.html +261 -0
  225. customeranalytics/web/app/home/templates/clv.html +211 -0
  226. customeranalytics/web/app/home/templates/cohorts.html +308 -0
  227. customeranalytics/web/app/home/templates/customer-segmentation.html +308 -0
  228. customeranalytics/web/app/home/templates/data-es.html +152 -0
  229. customeranalytics/web/app/home/templates/data-execute.html +397 -0
  230. customeranalytics/web/app/home/templates/delivery.html +404 -0
  231. customeranalytics/web/app/home/templates/funnel-customer.html +240 -0
  232. customeranalytics/web/app/home/templates/funnel-session.html +236 -0
  233. customeranalytics/web/app/home/templates/index.html +524 -0
  234. customeranalytics/web/app/home/templates/index2.html +515 -0
  235. customeranalytics/web/app/home/templates/page-403.html +46 -0
  236. customeranalytics/web/app/home/templates/page-404.html +45 -0
  237. customeranalytics/web/app/home/templates/page-500.html +45 -0
  238. customeranalytics/web/app/home/templates/pages-blank.html +33 -0
  239. customeranalytics/web/app/home/templates/pages-sign-in.html +67 -0
  240. customeranalytics/web/app/home/templates/pages-sign-up.html +61 -0
  241. customeranalytics/web/app/home/templates/product.html +203 -0
  242. customeranalytics/web/app/home/templates/profile.html +1009 -0
  243. customeranalytics/web/app/home/templates/rfm.html +254 -0
  244. customeranalytics/web/app/home/templates/search.html +167 -0
  245. customeranalytics/web/app/home/templates/settings.html +205 -0
  246. customeranalytics/web/app/home/templates/stats-desc.html +230 -0
  247. customeranalytics/web/app/home/templates/stats-purchase.html +221 -0
  248. customeranalytics/web/config.py +30 -0
  249. customeranalytics/web/db.sqlite3 +0 -0
  250. customeranalytics/web/run.py +30 -0
  251. customeranalytics-0.1.dist-info/METADATA +1102 -0
  252. customeranalytics-0.1.dist-info/RECORD +254 -0
  253. customeranalytics-0.1.dist-info/WHEEL +4 -0
  254. 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
+