Files
liqiang b119135836
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
2026-08-20 13:12:50 +00:00

244 lines
8.0 KiB
Python

"""
Leaderboard calculation and analysis
"""
import pandas as pd
import numpy as np
from typing import Dict, List, Tuple
from tqdm import tqdm
from elo_rating import EloRatingSystem
def build_leaderboard(df: pd.DataFrame,
initial_rating: float = 1000.0,
k_factor: float = 32.0,
show_progress: bool = True) -> EloRatingSystem:
"""
Build Elo leaderboard from voting data.
Args:
df: DataFrame with columns 'model_a', 'model_b', 'winner'
initial_rating: Starting rating for all models
k_factor: Elo learning rate
show_progress: Whether to show progress bar
Returns:
EloRatingSystem with final ratings
"""
elo = EloRatingSystem(initial_rating=initial_rating, k_factor=k_factor)
iterator = tqdm(df.iterrows(), total=len(df), desc="Processing matches") if show_progress else df.iterrows()
for idx, row in iterator:
model_a = row['model_a']
model_b = row['model_b']
winner = row['winner']
elo.update_ratings(model_a, model_b, winner)
return elo
def calculate_win_rate_matrix_from_data(df: pd.DataFrame) -> pd.DataFrame:
"""
Calculate empirical win rate matrix directly from vote data.
Args:
df: DataFrame with columns 'model_a', 'model_b', 'winner'
Returns:
DataFrame with win rates (rows beat columns)
"""
# Get all unique models
all_models = sorted(set(df['model_a'].unique()) | set(df['model_b'].unique()))
# Initialize counts
wins = {model: {opponent: 0 for opponent in all_models} for model in all_models}
total = {model: {opponent: 0 for opponent in all_models} for model in all_models}
# Count wins and totals
for _, row in df.iterrows():
model_a = row['model_a']
model_b = row['model_b']
winner = row['winner']
total[model_a][model_b] += 1
total[model_b][model_a] += 1
if winner == 'model_a':
wins[model_a][model_b] += 1
elif winner == 'model_b':
wins[model_b][model_a] += 1
else: # tie
wins[model_a][model_b] += 0.5
wins[model_b][model_a] += 0.5
# Calculate win rates
win_rates = {}
for model in all_models:
win_rates[model] = {}
for opponent in all_models:
if model == opponent:
win_rates[model][opponent] = 0.5
elif total[model][opponent] > 0:
win_rates[model][opponent] = wins[model][opponent] / total[model][opponent]
else:
win_rates[model][opponent] = np.nan
# Convert to DataFrame
win_rate_df = pd.DataFrame(win_rates).T
win_rate_df = win_rate_df[all_models] # Ensure consistent ordering
return win_rate_df
def compare_win_rates(elo_system: EloRatingSystem, empirical_df: pd.DataFrame) -> pd.DataFrame:
"""
Compare predicted win rates from Elo with empirical win rates.
Args:
elo_system: Trained Elo rating system
empirical_df: DataFrame with empirical win rates
Returns:
DataFrame with comparison statistics
"""
models = empirical_df.index.tolist()
comparisons = []
for model_a in models:
for model_b in models:
if model_a != model_b:
empirical = empirical_df.loc[model_a, model_b]
if not np.isnan(empirical):
predicted = elo_system.calculate_win_probability(model_a, model_b)
error = abs(predicted - empirical)
comparisons.append({
'model_a': model_a,
'model_b': model_b,
'empirical': empirical,
'predicted': predicted,
'error': error
})
cols = ['model_a', 'model_b', 'empirical', 'predicted', 'error']
if not comparisons:
return pd.DataFrame(columns=cols)
comparison_df = pd.DataFrame(comparisons, columns=cols)
return comparison_df
def build_historical_leaderboards(df: pd.DataFrame,
time_slices: List[Tuple],
initial_rating: float = 1000.0,
k_factor: float = 32.0) -> List[Tuple]:
"""
Build leaderboard snapshots at different time points.
Args:
df: Full voting DataFrame
time_slices: List of (end_date, slice_df) tuples from get_time_slices
initial_rating: Starting rating
k_factor: Elo learning rate
Returns:
List of (date, leaderboard_data) tuples
"""
historical_leaderboards = []
for end_date, slice_df in tqdm(time_slices, desc="Building historical leaderboards"):
elo = build_leaderboard(slice_df, initial_rating, k_factor, show_progress=False)
leaderboard = elo.get_leaderboard()
# Convert to DataFrame for easier handling
lb_df = pd.DataFrame(leaderboard, columns=['model', 'rating', 'matches', 'wins'])
lb_df['date'] = end_date
lb_df['rank'] = range(1, len(lb_df) + 1)
historical_leaderboards.append((end_date, lb_df))
return historical_leaderboards
def get_rating_history(historical_leaderboards: List[Tuple]) -> pd.DataFrame:
"""
Extract rating history for all models over time.
Args:
historical_leaderboards: List of (date, leaderboard_df) tuples
Returns:
DataFrame with columns: date, model, rating, rank
"""
all_data = []
for date, lb_df in historical_leaderboards:
for _, row in lb_df.iterrows():
all_data.append({
'date': date,
'model': row['model'],
'rating': row['rating'],
'rank': row['rank'],
'matches': row['matches'],
'wins': row['wins']
})
cols = ['date', 'model', 'rating', 'rank', 'matches', 'wins']
if not all_data:
return pd.DataFrame(columns=cols)
history_df = pd.DataFrame(all_data)
return history_df
def analyze_rating_changes(history_df: pd.DataFrame, top_n: int = 20) -> pd.DataFrame:
"""
Analyze rating changes over time for top models.
Args:
history_df: DataFrame from get_rating_history
top_n: Number of top models to analyze
Returns:
DataFrame with change statistics
"""
stats_cols = [
'model', 'final_rating', 'initial_rating', 'rating_change',
'max_rating', 'min_rating', 'volatility', 'total_matches',
]
if history_df is None or len(history_df) == 0:
return pd.DataFrame(columns=stats_cols)
# Get final ratings
final_date = history_df['date'].max()
final_ratings = history_df[history_df['date'] == final_date].nlargest(top_n, 'rating')
top_models = final_ratings['model'].tolist()
# Calculate statistics for each model
stats = []
for model in top_models:
model_data = history_df[history_df['model'] == model].sort_values('date')
if len(model_data) > 0:
initial_rating = model_data.iloc[0]['rating']
final_rating = model_data.iloc[-1]['rating']
max_rating = model_data['rating'].max()
min_rating = model_data['rating'].min()
rating_change = final_rating - initial_rating
volatility = model_data['rating'].std()
stats.append({
'model': model,
'final_rating': final_rating,
'initial_rating': initial_rating,
'rating_change': rating_change,
'max_rating': max_rating,
'min_rating': min_rating,
'volatility': volatility,
'total_matches': model_data.iloc[-1]['matches']
})
if not stats:
return pd.DataFrame(columns=stats_cols)
stats_df = pd.DataFrame(stats).sort_values('final_rating', ascending=False)
return stats_df