DawnC commited on
Commit
bf54860
1 Parent(s): e5fb6cc

Update scoring_calculation_system.py

Browse files
Files changed (1) hide show
  1. scoring_calculation_system.py +140 -145
scoring_calculation_system.py CHANGED
@@ -1509,199 +1509,194 @@ 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
- 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 = {
1584
- 'space': 0.35,
1585
- 'exercise': 0.30,
1586
- 'experience': 0.20,
1587
- 'grooming': 0.15,
1588
- 'health': 0.10,
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
 
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
+ """
1518
+ # 1. 基礎特徵評估 - 更極端的調整
1519
+ def evaluate_feature_score(feature: str) -> float:
1520
+ score = scores[feature]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1521
 
1522
+ if feature == 'exercise':
1523
+ exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1524
+ exercise_time = user_prefs.exercise_time
 
 
1525
 
1526
+ if exercise_needs == 'VERY HIGH':
1527
+ if exercise_time < 120:
1528
+ return score * 0.4 # 嚴重懲罰運動不足
1529
+ elif exercise_time > 150:
1530
+ return min(1.0, score * 1.5) # 顯著獎勵充足運動
1531
+ elif exercise_needs == 'LOW' and exercise_time > 120:
1532
+ return score * 0.6 # 懲罰過度運動
1533
+
1534
+ elif feature == 'space':
1535
+ size = breed_info['Size']
1536
+ if user_prefs.living_space == 'apartment':
1537
+ if size in ['Large', 'Giant']:
1538
+ return score * 0.3 # 更嚴格的空間限制
1539
+ elif size == 'Small':
1540
+ return min(1.0, score * 1.4) # 更高的小型犬獎勵
1541
+
1542
+ elif feature == 'experience':
1543
+ care_level = breed_info.get('Care Level', 'MODERATE')
1544
+ if care_level == 'High' and user_prefs.experience_level == 'beginner':
1545
+ return score * 0.4
1546
+ elif care_level == 'Low' and user_prefs.experience_level == 'advanced':
1547
+ return score * 0.8 # 略微降低過度資格
1548
+
1549
+ return score
1550
 
1551
+ # 2. 計算調整後的分數
1552
  adjusted_scores = {
1553
+ feature: evaluate_feature_score(feature)
1554
+ for feature in scores.keys()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1555
  }
1556
 
1557
+ # 3. 動態權重分配 - 根據條件強化關鍵特徵
1558
+ def calculate_feature_weight(feature: str) -> float:
1559
+ base_weights = {
1560
+ 'space': 0.35,
1561
+ 'exercise': 0.30,
1562
+ 'experience': 0.20,
1563
+ 'grooming': 0.15,
1564
+ 'health': 0.10,
1565
+ 'noise': 0.10
1566
+ }
1567
 
1568
+ weight = base_weights[feature]
 
 
 
1569
 
1570
+ # 條件相關的權重調整
1571
+ if feature == 'space' and user_prefs.living_space == 'apartment':
1572
+ weight *= 1.6 # 加強空間限制的影響
 
 
 
 
 
1573
 
1574
+ elif feature == 'exercise':
1575
+ if user_prefs.exercise_time > 150:
1576
+ weight *= 1.4
1577
+ elif user_prefs.exercise_time < 60:
1578
+ weight *= 1.3
1579
+
1580
+ elif feature == 'experience':
1581
+ if user_prefs.experience_level in ['beginner', 'advanced']:
1582
+ weight *= 1.3 # 強化極端經驗等級的影響
1583
+
1584
+ return weight
 
 
 
 
 
1585
 
1586
+ # 4. 計算加權分數
1587
+ weights = {feature: calculate_feature_weight(feature)
1588
+ for feature in scores.keys()}
1589
 
1590
+ # 正規化權重
1591
+ total_weight = sum(weights.values())
1592
+ normalized_weights = {k: v/total_weight for k, v in weights.items()}
1593
 
1594
+ # 5. 計算基礎分數 - 分離主要和次要特徵
1595
+ primary_features = {'space', 'exercise', 'experience'}
1596
+ secondary_features = set(scores.keys()) - primary_features
1597
+
1598
+ primary_score = sum(adjusted_scores[f] * normalized_weights[f]
1599
+ for f in primary_features)
1600
+ secondary_score = sum(adjusted_scores[f] * normalized_weights[f]
1601
+ for f in secondary_features)
1602
+
1603
+ # 6. 特殊條件評估
1604
+ condition_multiplier = 1.0
1605
+
1606
+ # 空間條件
1607
+ if user_prefs.living_space == 'apartment':
1608
+ if breed_info['Size'] in ['Large', 'Giant']:
1609
+ condition_multiplier *= 0.7
1610
+ elif breed_info['Size'] == 'Small':
1611
+ condition_multiplier *= 1.2
1612
+
1613
+ # 運動條件
1614
+ exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
1615
+ if exercise_needs == 'VERY HIGH' and user_prefs.exercise_time < 120:
1616
+ condition_multiplier *= 0.8
1617
+ elif exercise_needs == 'LOW' and user_prefs.exercise_time > 150:
1618
+ condition_multiplier *= 0.85
1619
+
1620
+ # 7. 計算最終分數
1621
+ base_score = (primary_score * 0.7 + secondary_score * 0.3)
1622
  breed_bonus = calculate_breed_bonus(breed_info, user_prefs)
1623
 
1624
+ final_score = (base_score * condition_multiplier * 0.8) + (breed_bonus * 0.2)
1625
+
 
1626
  return max(0.0, min(1.0, final_score))
1627
 
1628
 
1629
  def amplify_score_extreme(score: float) -> float:
1630
+ """
1631
+ 優化的分數映射函數
1632
+
1633
+ 主要改進:
1634
+ 1. 更細緻的分數區間劃分,讓分數轉換更平滑
1635
+ 2. 根據不同分數段使用不同的轉換曲線
1636
+ 3. 確保極端分數能得到更極端的映射
1637
+
1638
+ 分數區間的設計邏輯:
1639
+ - 極差匹配 (0.0-0.2): 60-63% - 快速的線性增長
1640
+ - 差匹配 (0.2-0.4): 63-68% - 緩慢的增長
1641
+ - 中等匹配 (0.4-0.6): 68-75% - ��定的線性增長
1642
+ - 良好匹配 (0.6-0.75): 75-85% - 加速增長
1643
+ - 優秀匹配 (0.75-0.9): 85-92% - 減速增長
1644
+ - 完美匹配 (0.9-1.0): 92-95% - 非常緩慢的增長
1645
  """
1646
  ranges = {
1647
+ 'very_poor': {
1648
+ 'range': (0.0, 0.2),
1649
  'out_min': 0.60,
1650
+ 'out_max': 0.63,
1651
+ 'curve': 1.0 # 線性
1652
+ },
1653
+ 'poor': {
1654
+ 'range': (0.2, 0.4),
1655
+ 'out_min': 0.63,
1656
  'out_max': 0.68,
1657
+ 'curve': 1.2 # 稍微非線性
1658
  },
1659
+ 'mediocre': {
1660
+ 'range': (0.4, 0.6),
1661
  'out_min': 0.68,
1662
  'out_max': 0.75,
1663
+ 'curve': 1.0 # 線性
 
 
 
 
 
 
1664
  },
1665
  'good': {
1666
+ 'range': (0.6, 0.75),
1667
+ 'out_min': 0.75,
1668
+ 'out_max': 0.85,
1669
+ 'curve': 0.8 # 加速增長
1670
  },
1671
  'excellent': {
1672
+ 'range': (0.75, 0.9),
1673
+ 'out_min': 0.85,
1674
  'out_max': 0.92,
1675
+ 'curve': 1.2 # 減速增長
1676
  },
1677
  'perfect': {
1678
  'range': (0.9, 1.0),
1679
  'out_min': 0.92,
1680
  'out_max': 0.95,
1681
+ 'curve': 1.5 # 強烈的減速
1682
  }
1683
  }
1684
+
1685
+ # 找出分數所屬區間並進行映射
1686
  for config in ranges.values():
1687
  range_min, range_max = config['range']
1688
  if range_min <= score <= range_max:
1689
+ # 計算區間內的相對位置(0-1)
1690
  position = (score - range_min) / (range_max - range_min)
1691
 
1692
+ # 應用非線性曲線來調整增長速度
1693
  position = pow(position, config['curve'])
1694
 
1695
  # 映射到輸出範圍
1696
  result = config['out_min'] + (config['out_max'] - config['out_min']) * position
1697
 
1698
+ # 確保結果精確到小數點後三位
1699
  return round(result, 3)
1700
 
1701
+ # 處理超出範圍的情況
1702
  return 0.60 if score < 0.0 else 0.95