(region_data, selected_categories, forecast_months)
| 31 | forecast_insights(region_data, selected_categories, forecast_periods) |
| 32 | |
| 33 | def create_multi_category_forecast(region_data, selected_categories, forecast_months): |
| 34 | all_bnf = region_data.groupby('BNF_CHAPTER_PLUS_CODE')['TOTAL_COST'].sum() |
| 35 | |
| 36 | fig = go.Figure() |
| 37 | |
| 38 | historical_colors = [ |
| 39 | '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD', |
| 40 | '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9', '#F8C471', '#82E0AA', |
| 41 | '#F1948A', '#85C1E9', '#D7BDE2', '#A9CCE3', '#FAD7A0', '#ABEBC6', |
| 42 | '#F5B7B1', '#AED6F1', '#D5A6BD', '#A2D9CE', '#F9E79F', '#D2B4DE' |
| 43 | ] |
| 44 | |
| 45 | forecast_colors = [ |
| 46 | '#FF8E8E', '#6EDDD6', '#65C7E1', '#A6DEB4', '#FFF2B7', '#EDB0ED', |
| 47 | '#A8E8D8', '#F7EC7F', '#CB9FDE', '#95D1F9', '#F8D481', '#92F0BA', |
| 48 | '#F1A49A', '#95D1F9', '#E7CDE2', '#B9DCE3', '#FAE7B0', '#BBEBD6', |
| 49 | '#F5C7C1', '#BEE6F1', '#E5B6CD', '#B2E9DE', '#F9F79F', '#E2C4EE' |
| 50 | ] |
| 51 | |
| 52 | forecast_start_date = None |
| 53 | all_dates = [] |
| 54 | all_categories_data = {} |
| 55 | failed_categories = [] |
| 56 | filtered_bnf = [bnf for bnf in all_bnf.index if bnf in selected_categories] |
| 57 | for i, bnf_code in enumerate(filtered_bnf): |
| 58 | bnf_data = region_data[region_data['BNF_CHAPTER_PLUS_CODE'] == bnf_code] |
| 59 | ts_data = bnf_data.groupby('YEAR_MONTH')['TOTAL_COST'].sum().reset_index() |
| 60 | |
| 61 | if len(ts_data) >= 3: |
| 62 | category_parts = bnf_code.split(":") |
| 63 | if len(category_parts) >= 2: |
| 64 | category_short = f"{category_parts[0].strip()}: {category_parts[1].strip()}" |
| 65 | else: |
| 66 | category_short = bnf_code.strip() |
| 67 | |
| 68 | try: |
| 69 | forecast_df = train_arima(ts_data, forecast_months) |
| 70 | |
| 71 | if forecast_start_date is None: |
| 72 | forecast_start_date = forecast_df['YEAR_MONTH'].iloc[0] |
| 73 | |
| 74 | combined_dates = list(ts_data['YEAR_MONTH']) + list(forecast_df['YEAR_MONTH']) |
| 75 | combined_values = list(ts_data['TOTAL_COST']) + list(forecast_df['FORECAST']) |
| 76 | |
| 77 | all_dates.extend(combined_dates) |
| 78 | all_categories_data[category_short] = { |
| 79 | 'dates': combined_dates, |
| 80 | 'values': combined_values, |
| 81 | 'historical_end': len(ts_data) - 1, |
| 82 | 'historical_color': historical_colors[i % len(historical_colors)], |
| 83 | 'forecast_color': forecast_colors[i % len(forecast_colors)] |
| 84 | } |
| 85 | except ValueError as e: |
| 86 | failed_categories.append(category_short) |
| 87 | continue |
| 88 | |
| 89 | if failed_categories: |
| 90 | st.warning(f"ARIMA modeling failed for {len(failed_categories)} categories: {', '.join(failed_categories[:5])}{'...' if len(failed_categories) > 5 else ''}") |
no test coverage detected