You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CompanyStatsOverview.php 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <?php
  2. namespace App\Filament\Pages\Widgets\Companies\Charts;
  3. use App\Models\Company;
  4. use Filament\Widgets\StatsOverviewWidget;
  5. class CompanyStatsOverview extends StatsOverviewWidget
  6. {
  7. protected int|string|array $columnSpan = 3;
  8. protected function getColumns(): int
  9. {
  10. return 3;
  11. }
  12. /**
  13. * Holt's Linear Trend Method
  14. */
  15. protected function holtLinearTrend($data, $alpha, $beta): array
  16. {
  17. $level = $data[0];
  18. $trend = $data[1] - $data[0];
  19. $forecast = [];
  20. for ($i = 0; $i < count($data); $i++) {
  21. $prev_level = $level;
  22. $level = $alpha * $data[$i] + (1 - $alpha) * ($prev_level + $trend);
  23. $trend = $beta * ($level - $prev_level) + (1 - $beta) * $trend;
  24. $forecast[] = $level + $trend;
  25. }
  26. return $forecast;
  27. }
  28. /**
  29. * Adjusts the alpha and beta parameters based on the model's performance
  30. */
  31. protected function adjustTrendParameters($data, $alpha, $beta): array
  32. {
  33. $minError = PHP_INT_MAX;
  34. $bestAlpha = $alpha;
  35. $bestBeta = $beta;
  36. // try different alpha and beta values within a reasonable range
  37. for ($alpha = 0.1; $alpha <= 1; $alpha += 0.1) {
  38. for ($beta = 0.1; $beta <= 1; $beta += 0.1) {
  39. $forecast = $this->holtLinearTrend($data, $alpha, $beta);
  40. $error = $this->calculateError($data, $forecast);
  41. if ($error < $minError) {
  42. $minError = $error;
  43. $bestAlpha = $alpha;
  44. $bestBeta = $beta;
  45. }
  46. }
  47. }
  48. return [$bestAlpha, $bestBeta];
  49. }
  50. /**
  51. * Calculates the sum of squared errors between the actual data and the forecast
  52. */
  53. protected function calculateError($data, $forecast): float
  54. {
  55. $error = 0;
  56. for ($i = 0; $i < count($data); $i++) {
  57. $error += pow($data[$i] - $forecast[$i], 2);
  58. }
  59. return $error;
  60. }
  61. /**
  62. * Chart Options
  63. */
  64. protected function getCards(): array
  65. {
  66. // Define constants
  67. $alpha = 0.8;
  68. $beta = 0.2;
  69. // Define time variables
  70. $startOfYear = today()->startOfYear();
  71. $today = today();
  72. // Get Company Data
  73. $companyData = Company::selectRaw("COUNT(*) as aggregate, YEARWEEK(created_at, 3) as week")
  74. ->whereBetween('created_at', [$startOfYear, $today])
  75. ->groupByRaw('week')
  76. ->get();
  77. // Initialize weeks
  78. $weeks = [];
  79. for ($week = $startOfYear->copy(); $week->lte($today); $week->addWeek()) {
  80. $weeks[$week->format('oW')] = 0;
  81. }
  82. // Get Weekly Data for Company Data
  83. $weeklyData = collect($weeks)->mapWithKeys(static function ($value, $week) use ($companyData) {
  84. $matchingData = $companyData->firstWhere('week', $week);
  85. return [$week => $matchingData ? $matchingData->aggregate : 0];
  86. });
  87. // Calculate total companies per week
  88. $totalCompanies = $weeklyData->reduce(static function ($carry, $value) {
  89. $carry[] = ($carry ? end($carry) : 0) + $value;
  90. return $carry;
  91. }, []);
  92. // Calculate new companies and percentage change per week
  93. $newCompanies = [0];
  94. $weeklyPercentageChange = [0];
  95. for ($i = 1; $i < count($totalCompanies); $i++) {
  96. $newCompanies[] = $totalCompanies[$i] - $totalCompanies[$i - 1];
  97. $weeklyPercentageChange[] = ($newCompanies[$i] / $totalCompanies[$i - 1]) * 100;
  98. }
  99. // Calculate average weekly growth rate
  100. $totalWeeks = $startOfYear->diffInWeeks($today);
  101. $averageWeeklyGrowthRate = round(array_sum($weeklyPercentageChange) / $totalWeeks, 2);
  102. $weeklyDataArray = $weeklyData->values()->toArray();
  103. // Adjust alpha and beta parameters
  104. [$alpha, $beta] = $this->adjustTrendParameters($weeklyDataArray, $alpha, $beta);
  105. // Calculate Holt's Linear Trend Forecast for next week
  106. $holtForecast = $this->holtLinearTrend($weeklyDataArray, $alpha, $beta);
  107. $expectedNewCompanies = round(end($holtForecast));
  108. // Company Stats Overview Cards
  109. return [
  110. StatsOverviewWidget\Card::make("New Companies Forecast (Holt's Linear Trend)", $expectedNewCompanies),
  111. StatsOverviewWidget\Card::make('Average Weekly Growth Rate', $averageWeeklyGrowthRate . '%'),
  112. StatsOverviewWidget\Card::make('Personal Companies', Company::sum('personal_company')),
  113. ];
  114. }
  115. }