11#!/usr/bin/env python3
22
3+ """Aggregate results from multiple llm_as_judge.json files
4+ and save as a compressed parquet file for efficient storage and loading.
5+ """
6+
37import argparse
48import json
59from pathlib import Path
610from typing import Any
711
12+ import pandas as pd
13+
814from codeclash .analysis .llm_as_judge .utils import Instance
915from codeclash .utils .log import get_logger
1016
1117logger = get_logger ("AggregateResults" , emoji = "📊" )
1218
1319
14- def aggregate_results (input_dir : Path ) -> dict [ str , Any ] :
15- """Aggregate all llm_as_judge.json results from the input directory.
20+ def aggregate_results_to_dataframe (input_dir : Path ) -> pd . DataFrame :
21+ """Aggregate all llm_as_judge.json results from the input directory into a DataFrame .
1622
1723 Returns:
18- Dictionary with structure {data_id: {instance_id: result_data}}
24+ DataFrame with flattened structure containing all evaluation data
1925 """
20- aggregated = {}
26+ rows = []
2127 llm_judge_files = list (input_dir .rglob ("llm_as_judge.json" ))
2228
2329 logger .info (f"Found { len (llm_judge_files )} llm_as_judge.json files" )
@@ -33,51 +39,58 @@ def aggregate_results(input_dir: Path) -> dict[str, Any]:
3339
3440 file_data = json .loads (content )
3541
36- # Merge each data_id from this file into the aggregated results
42+ # Process each data_id and instance
3743 for data_id , instances in file_data .items ():
38- if data_id not in aggregated :
39- aggregated [data_id ] = {}
40-
41- # Check for duplicate instance_ids
4244 for instance_id , instance_data in instances .items ():
43- if instance_id in aggregated [data_id ]:
44- logger .warning (f"Duplicate instance_id '{ instance_id } ' found in { file_path } " )
45-
46- # Add model info
45+ # Extract instance metadata
4746 instance = Instance .model_validate (instance_data ["instance" ])
4847 model_name , opponent_model_name = instance .get_lm_name_self_opponent ()
49- instance_data .setdefault ("info" , {})
50- instance_data ["info" ]["model_name" ] = model_name
51- instance_data ["info" ]["opponent_model_name" ] = opponent_model_name
5248
53- aggregated [data_id ][instance_id ] = instance_data
49+ # Create a flat row with all information
50+ row = {
51+ "data_id" : data_id ,
52+ "instance_id" : instance_id ,
53+ "tournament_name" : instance .tournament_name ,
54+ "player_name" : instance .player_name ,
55+ "round_number" : instance .round_number ,
56+ "model_name" : model_name ,
57+ "opponent_model_name" : opponent_model_name ,
58+ }
59+
60+ # Add all evaluation results
61+ if "result" in instance_data :
62+ result_data = instance_data ["result" ]
63+ for key , value in result_data .items ():
64+ row [key ] = value
65+
66+ rows .append (row )
5467
5568 except json .JSONDecodeError as e :
5669 logger .error (f"Failed to parse JSON in { file_path } : { e } " )
5770 except Exception as e :
5871 logger .error (f"Error processing { file_path } : { e } " , exc_info = True )
5972
60- total_instances = sum ( len ( instances ) for instances in aggregated . values () )
61- logger .info (f"Aggregated { total_instances } instances across { len (aggregated )} data versions " )
73+ df = pd . DataFrame ( rows )
74+ logger .info (f"Created DataFrame with { len ( df ) } rows and { len (df . columns )} columns " )
6275
63- return aggregated
76+ return df
6477
6578
6679def main () -> None :
67- parser = argparse .ArgumentParser (description = "Aggregate LLM-as-judge evaluation results" )
80+ parser = argparse .ArgumentParser (description = "Aggregate LLM-as-judge evaluation results to Parquet " )
6881 parser .add_argument ("input_dir" , type = Path , help = "Path to the input directory containing tournament results" )
6982 parser .add_argument ("-o" , "--output-file" , type = Path ,
70- help = "Path to the output file" , default = "aggregated_results.json " )
83+ help = "Path to the output Parquet file" , default = "aggregated_results.parquet " )
7184 args = parser .parse_args ()
7285
7386 if not args .input_dir .exists ():
7487 logger .error (f"Input directory does not exist: { args .input_dir } " )
7588 return
7689
7790 logger .info (f"Aggregating results from { args .input_dir } " )
78- aggregated = aggregate_results (args .input_dir )
91+ df = aggregate_results_to_dataframe (args .input_dir )
7992
80- args . output_file . write_text ( json . dumps ( aggregated , indent = 2 ) )
93+ df . to_parquet ( args . output_file , compression = "snappy" , index = False )
8194 logger .info (f"Wrote aggregated results to { args .output_file } " )
8295
8396
0 commit comments