DawnC commited on
Commit
32e555f
1 Parent(s): 6126763

Update scoring_calculation_system.py

Browse files
Files changed (1) hide show
  1. scoring_calculation_system.py +145 -124
scoring_calculation_system.py CHANGED
@@ -1509,38 +1509,75 @@ def calculate_environmental_fit(breed_info: dict, user_prefs: UserPreferences) -
1509
 
1510
 
1511
  def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
 
 
 
 
 
 
1512
  """
1513
- 改進的品種相容性評分系統,提供更明顯的分數差異和更準確的品種匹配
1514
-
1515
- 主要改進:
1516
- 1. 提高關鍵參數權重
1517
- 2. 加強條件權重調整
1518
- 3. 更嚴格的不適配懲罰
1519
- 4. 非線性分數調整
1520
- """
1521
- # 關鍵不適配參數檢查 - 加強懲罰機制
1522
- critical_params = {
1523
  'space': {
1524
- 'threshold': 0.35,
1525
- 'conditions': lambda p: True,
1526
- 'penalty': 0.3
1527
  },
1528
- 'noise': {
1529
- 'threshold': 0.35,
1530
- 'conditions': lambda p: p.living_space == 'apartment',
1531
- 'penalty': 0.35
 
1532
  },
1533
  'experience': {
1534
- 'threshold': 0.35,
1535
- 'conditions': lambda p: p.experience_level == 'beginner',
1536
- 'penalty': 0.35
1537
  }
1538
  }
1539
 
1540
- # 檢查關鍵不適配
1541
- for param, config in critical_params.items():
1542
- if scores[param] < config['threshold'] and config['conditions'](user_prefs):
1543
- return config['penalty']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1544
 
1545
  # 基礎權重設定
1546
  base_weights = {
@@ -1552,135 +1589,119 @@ def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreference
1552
  'noise': 0.10
1553
  }
1554
 
1555
- # 計算各項指標的調整後分數
1556
- adjusted_scores = {}
1557
- for param, score in scores.items():
1558
- # 基礎分數調整:優秀匹配得到更高分數
1559
- if score > 0.8:
1560
- adjusted_scores[param] = min(1.0, score * 1.3) # 優秀匹配額外加分
1561
- elif score < 0.4:
1562
- adjusted_scores[param] = score * 0.7 # 較差匹配更大懲罰
1563
- else:
1564
- adjusted_scores[param] = score
1565
-
1566
- # 權重動態調整
1567
- adjusted_weights = {}
1568
- for param, weight in base_weights.items():
1569
- multiplier = 1.0
1570
 
1571
- # 空間適配性調整
1572
- if param == 'space':
1573
- if user_prefs.living_space == 'apartment':
1574
- if breed_info['Size'] in ['Large', 'Giant']:
1575
- multiplier *= 0.5 # 大型犬在公寓極不適合
1576
- elif breed_info['Size'] == 'Small':
1577
- multiplier *= 1.4 # 小型犬在公寓更合適
1578
- elif user_prefs.living_space == 'house_large':
1579
- if breed_info['Size'] in ['Large', 'Giant']:
1580
- multiplier *= 1.3 # 大型犬在大房子更合適
1581
-
1582
- # 運動需求調整
1583
- elif param == 'exercise':
1584
- exercise_needs = breed_info.get('Exercise Needs', 'Moderate').upper()
1585
- if exercise_needs == 'VERY HIGH':
1586
- if user_prefs.exercise_time > 150:
1587
- multiplier *= 1.4 # 高運動量需求與高運動時間匹配
1588
- elif user_prefs.exercise_time < 60:
1589
- multiplier *= 0.6 # 運動時間嚴重不足
1590
- elif exercise_needs == 'LOW' and user_prefs.exercise_time > 120:
1591
- multiplier *= 0.8 # 過度運動對低運動需求品種不利
1592
-
1593
- # 經驗需求調整
1594
- elif param == 'experience':
1595
- if breed_info.get('Care Level') == 'High':
1596
- if user_prefs.experience_level == 'beginner':
1597
- multiplier *= 0.6
1598
- elif user_prefs.experience_level == 'advanced':
1599
- multiplier *= 1.3
1600
-
1601
- adjusted_weights[param] = weight * multiplier
1602
-
1603
- # 重新正規化權重
1604
- total_weight = sum(adjusted_weights.values())
1605
- normalized_weights = {k: v/total_weight for k, v in adjusted_weights.items()}
1606
-
1607
- # 計算加權分數
1608
- weighted_scores = {}
1609
- for param, weight in normalized_weights.items():
1610
- weighted_scores[param] = adjusted_scores[param] * weight
1611
 
1612
- # 分開計算主要參數和次要參數
 
 
 
 
 
1613
  primary_params = {'space', 'exercise', 'experience'}
1614
- primary_score = sum(weighted_scores[p] for p in primary_params) / sum(normalized_weights[p] for p in primary_params)
1615
- secondary_score = sum(weighted_scores[p] for p in weighted_scores if p not in primary_params) / \
1616
- sum(normalized_weights[p] for p in normalized_weights if p not in primary_params)
1617
 
1618
- # 綜合評分,主要參數占更大權重
1619
- base_score = (primary_score * 0.7) + (secondary_score * 0.3)
1620
 
1621
- # 計算完美匹配加成
1622
- perfect_match_bonus = 0.0
 
 
1623
  if all(adjusted_scores[p] > 0.8 for p in primary_params):
1624
- perfect_match_bonus = 0.1
1625
-
1626
- # 計算最終分數
1627
- final_score = base_score + perfect_match_bonus
 
1628
 
1629
- # 品種特性加成
1630
  breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
1631
 
1632
- # 整合最終分數
1633
- final_score = (final_score * 0.8) + (breed_bonus * 0.2)
1634
 
1635
- return final_score
 
1636
 
1637
  def amplify_score_extreme(score: float) -> float:
 
 
 
 
 
1638
  """
1639
- 將原始分數(0-1範圍)映射到最終評分範圍(60-95%)
1640
-
1641
- 分數映射邏輯:
1642
- - 0-0.3: 60-70% (較差匹配)
1643
- - 0.3-0.6: 70-80% (中等匹配)
1644
- - 0.6-0.8: 80-90% (良好匹配)
1645
- - 0.8-1.0: 90-95% (優秀匹配)
1646
-
1647
- 每個區間使用線性映射,確保相同輸入產生相同輸出
1648
- """
1649
- # 定義分數區間和對應的輸出範圍
1650
  ranges = {
1651
  'poor': {
1652
  'range': (0.0, 0.3),
1653
- 'out_min': 0.6,
1654
- 'out_max': 0.7
 
 
 
 
 
 
 
1655
  },
1656
- 'mediocre': {
1657
- 'range': (0.3, 0.6),
1658
- 'out_min': 0.7,
1659
- 'out_max': 0.8
 
1660
  },
1661
  'good': {
1662
- 'range': (0.6, 0.8),
1663
- 'out_min': 0.8,
1664
- 'out_max': 0.9
 
1665
  },
1666
  'excellent': {
1667
- 'range': (0.8, 1.0),
1668
- 'out_min': 0.9,
1669
- 'out_max': 0.95
 
 
 
 
 
 
 
1670
  }
1671
  }
1672
 
1673
- # 找出分數所屬區間並進行映射
1674
  for config in ranges.values():
1675
  range_min, range_max = config['range']
1676
  if range_min <= score <= range_max:
 
1677
  position = (score - range_min) / (range_max - range_min)
1678
 
1679
- # 線性映射到目標範圍
 
 
 
1680
  result = config['out_min'] + (config['out_max'] - config['out_min']) * position
1681
 
1682
- # 返回固定精度的分數
1683
- return round(result, 1)
1684
 
1685
- # 處理超出範圍的情況
1686
- return 0.6 if score < 0.0 else 0.95
 
1509
 
1510
 
1511
  def calculate_breed_compatibility_score(scores: dict, user_prefs: UserPreferences, breed_info: dict) -> float:
1512
+ """
1513
+ 主要優化:
1514
+ 1. 更細緻的特徵匹配評估
1515
+ 2. 非線性的權重計算
1516
+ 3. 多層次的條件影響
1517
+ 4. 動態閾值調整
1518
  """
1519
+ # 關鍵特徵評估閾值
1520
+ feature_thresholds = {
 
 
 
 
 
 
 
 
1521
  'space': {
1522
+ 'apartment': {'Small': 0.9, 'Medium': 0.6, 'Large': 0.3, 'Giant': 0.2},
1523
+ 'house_small': {'Small': 0.8, 'Medium': 0.8, 'Large': 0.6, 'Giant': 0.4},
1524
+ 'house_large': {'Small': 0.7, 'Medium': 0.85, 'Large': 0.9, 'Giant': 0.9}
1525
  },
1526
+ 'exercise': {
1527
+ 'VERY HIGH': {'min': 120, 'optimal': 180, 'factor': 1.5},
1528
+ 'HIGH': {'min': 90, 'optimal': 120, 'factor': 1.3},
1529
+ 'MODERATE': {'min': 45, 'optimal': 90, 'factor': 1.1},
1530
+ 'LOW': {'min': 20, 'optimal': 45, 'factor': 0.9}
1531
  },
1532
  'experience': {
1533
+ 'beginner': {'High': 0.4, 'Moderate': 0.7, 'Low': 0.9},
1534
+ 'intermediate': {'High': 0.7, 'Moderate': 0.85, 'Low': 0.95},
1535
+ 'advanced': {'High': 0.9, 'Moderate': 0.95, 'Low': 1.0}
1536
  }
1537
  }
1538
 
1539
+ # 評估空間適配性
1540
+ def evaluate_space_compatibility():
1541
+ size = breed_info['Size']
1542
+ base_threshold = feature_thresholds['space'][user_prefs.living_space][size]
1543
+ space_score = scores['space']
1544
+
1545
+ # 根據空間類型調整評分
1546
+ if user_prefs.living_space == 'apartment' and size in ['Large', 'Giant']:
1547
+ space_score *= 0.5
1548
+ elif user_prefs.living_space == 'house_large' and size in ['Large', 'Giant']:
1549
+ space_score *= 1.2
1550
+
1551
+ return min(1.0, space_score * base_threshold)
1552
+
1553
+ # 評估運動需求匹配度
1554
+ def evaluate_exercise_compatibility():
1555
+ exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1556
+ config = feature_thresholds['exercise'][exercise_needs]
1557
+
1558
+ if user_prefs.exercise_time < config['min']:
1559
+ return scores['exercise'] * 0.6
1560
+ elif user_prefs.exercise_time >= config['optimal']:
1561
+ return min(1.0, scores['exercise'] * config['factor'])
1562
+ else:
1563
+ ratio = (user_prefs.exercise_time - config['min']) / (config['optimal'] - config['min'])
1564
+ return scores['exercise'] * (0.6 + ratio * 0.4)
1565
+
1566
+ # 評估經驗需求匹配度
1567
+ def evaluate_experience_compatibility():
1568
+ care_level = breed_info.get('Care Level', 'Moderate')
1569
+ base_score = feature_thresholds['experience'][user_prefs.experience_level][care_level]
1570
+ return min(1.0, scores['experience'] * base_score)
1571
+
1572
+ # 計算調整後的分數
1573
+ adjusted_scores = {
1574
+ 'space': evaluate_space_compatibility(),
1575
+ 'exercise': evaluate_exercise_compatibility(),
1576
+ 'experience': evaluate_experience_compatibility(),
1577
+ 'grooming': scores['grooming'],
1578
+ 'health': scores['health'],
1579
+ 'noise': scores['noise']
1580
+ }
1581
 
1582
  # 基礎權重設定
1583
  base_weights = {
 
1589
  'noise': 0.10
1590
  }
1591
 
1592
+ # 動態權重調整
1593
+ def calculate_dynamic_weights():
1594
+ weights = base_weights.copy()
 
 
 
 
 
 
 
 
 
 
 
 
1595
 
1596
+ # 空間權重調整
1597
+ if user_prefs.living_space == 'apartment':
1598
+ weights['space'] *= 1.4
1599
+ weights['noise'] *= 1.3
1600
+
1601
+ # 運動權重調整
1602
+ exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1603
+ if exercise_needs in ['VERY HIGH', 'HIGH']:
1604
+ weights['exercise'] *= 1.3
1605
+
1606
+ # 經驗權重調整
1607
+ if user_prefs.experience_level == 'beginner':
1608
+ weights['experience'] *= 1.4
1609
+
1610
+ # 重新正規化
1611
+ total = sum(weights.values())
1612
+ return {k: v/total for k, v in weights.items()}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1613
 
1614
+ # 計算最終分數
1615
+ weights = calculate_dynamic_weights()
1616
+ weighted_scores = {param: score * weights[param]
1617
+ for param, score in adjusted_scores.items()}
1618
+
1619
+ # 分開計算主要和次要參數
1620
  primary_params = {'space', 'exercise', 'experience'}
1621
+ primary_score = sum(weighted_scores[p] for p in primary_params)
1622
+ secondary_score = sum(weighted_scores[p] for p in weighted_scores if p not in primary_params)
 
1623
 
1624
+ # 計算基礎分數
1625
+ base_score = (primary_score * 0.7 + secondary_score * 0.3)
1626
 
1627
+ # 特殊條件加成或懲罰
1628
+ bonus = 0.0
1629
+
1630
+ # 完美匹配加成
1631
  if all(adjusted_scores[p] > 0.8 for p in primary_params):
1632
+ bonus += 0.1
1633
+
1634
+ # 極端不適配懲罰
1635
+ if any(adjusted_scores[p] < 0.4 for p in primary_params):
1636
+ bonus -= 0.15
1637
 
1638
+ # 整合品種特性加成
1639
  breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
1640
 
1641
+ # 計算最終分數
1642
+ final_score = (base_score + bonus) * 0.8 + breed_bonus * 0.2
1643
 
1644
+ return max(0.0, min(1.0, final_score))
1645
+
1646
 
1647
  def amplify_score_extreme(score: float) -> float:
1648
+ """
1649
+ 改進:
1650
+ 1. 更細緻的分數區間劃分
1651
+ 2. 非線性的分數轉換
1652
+ 3. 更合理的分數分布
1653
  """
 
 
 
 
 
 
 
 
 
 
 
1654
  ranges = {
1655
  'poor': {
1656
  'range': (0.0, 0.3),
1657
+ 'out_min': 0.60,
1658
+ 'out_max': 0.68,
1659
+ 'curve': 1.2 # 加強懲罰效果
1660
+ },
1661
+ 'below_average': {
1662
+ 'range': (0.3, 0.5),
1663
+ 'out_min': 0.68,
1664
+ 'out_max': 0.75,
1665
+ 'curve': 1.1
1666
  },
1667
+ 'average': {
1668
+ 'range': (0.5, 0.65),
1669
+ 'out_min': 0.75,
1670
+ 'out_max': 0.82,
1671
+ 'curve': 1.0
1672
  },
1673
  'good': {
1674
+ 'range': (0.65, 0.8),
1675
+ 'out_min': 0.82,
1676
+ 'out_max': 0.88,
1677
+ 'curve': 1.1
1678
  },
1679
  'excellent': {
1680
+ 'range': (0.8, 0.9),
1681
+ 'out_min': 0.88,
1682
+ 'out_max': 0.92,
1683
+ 'curve': 1.2
1684
+ },
1685
+ 'perfect': {
1686
+ 'range': (0.9, 1.0),
1687
+ 'out_min': 0.92,
1688
+ 'out_max': 0.95,
1689
+ 'curve': 1.3
1690
  }
1691
  }
1692
 
 
1693
  for config in ranges.values():
1694
  range_min, range_max = config['range']
1695
  if range_min <= score <= range_max:
1696
+ # 計算在區間內的相對位置
1697
  position = (score - range_min) / (range_max - range_min)
1698
 
1699
+ # 應用非線性曲線
1700
+ position = pow(position, config['curve'])
1701
+
1702
+ # 映射到輸出範圍
1703
  result = config['out_min'] + (config['out_max'] - config['out_min']) * position
1704
 
1705
+ return round(result, 3)
 
1706
 
1707
+ return 0.60 if score < 0.0 else 0.95