1212import pandas as pd
1313
1414from codeclash .analysis .llm_as_judge .categorize_actions import _all_categories as ACTION_CATEGORIES
15+ from codeclash .analysis .llm_as_judge .hallucination import claim_categories as CLAIM_CATEGORIES
16+ from codeclash .analysis .llm_as_judge .hallucination import source_categories as SOURCE_CATEGORIES
1517from codeclash .analysis .llm_as_judge .utils import Instance
1618from codeclash .utils .log import get_logger
1719
2022# Version constants for specific data_ids
2123BIG_QUESTIONS_VERSION = 7
2224ACTION_CATEGORIES_VERSION = 3
25+ HALLUCINATION_VERSION = 17
26+
27+ # Generate all hallucination category combinations
28+ HALLUCINATION_CATEGORIES = [f"{ claim } __{ source } " for claim in CLAIM_CATEGORIES for source in SOURCE_CATEGORIES ]
2329
2430
2531class ResultsAggregator :
@@ -28,6 +34,7 @@ class ResultsAggregator:
2834 def __init__ (self ):
2935 self .big_questions_data_id = f"big_questions_v{ BIG_QUESTIONS_VERSION } "
3036 self .action_categories_data_id = f"action_categories_v{ ACTION_CATEGORIES_VERSION } "
37+ self .hallucination_data_id = f"hallucination_v{ HALLUCINATION_VERSION } "
3138
3239 def aggregate_results_to_dataframe (self , input_dir : Path ) -> pd .DataFrame :
3340 """Aggregate all llm_as_judge.json results from the input directory into a DataFrame.
@@ -55,7 +62,11 @@ def aggregate_results_to_dataframe(self, input_dir: Path) -> pd.DataFrame:
5562 # Process each data_id and instance
5663 for data_id , instances in file_data .items ():
5764 # Only process allowed data_ids
58- if data_id not in [self .action_categories_data_id , self .big_questions_data_id ]:
65+ if data_id not in [
66+ self .action_categories_data_id ,
67+ self .big_questions_data_id ,
68+ self .hallucination_data_id ,
69+ ]:
5970 continue
6071
6172 for instance_id , instance_data in instances .items ():
@@ -78,17 +89,24 @@ def aggregate_results_to_dataframe(self, input_dir: Path) -> pd.DataFrame:
7889 # Count instances for each data_id source
7990 action_categories_count = 0
8091 big_questions_count = 0
92+ hallucination_count = 0
8193
8294 for row in rows :
8395 data_ids = row .get ("data_ids" , [])
8496 if self .action_categories_data_id in data_ids :
8597 action_categories_count += 1
8698 if self .big_questions_data_id in data_ids :
8799 big_questions_count += 1
100+ if self .hallucination_data_id in data_ids :
101+ hallucination_count += 1
88102
89103 logger .info (f"Created DataFrame with { len (df )} rows and { len (df .columns )} columns" )
90104 logger .info (f"Instances with { self .action_categories_data_id } : { action_categories_count } " )
91105 logger .info (f"Instances with { self .big_questions_data_id } : { big_questions_count } " )
106+ logger .info (f"Instances with { self .hallucination_data_id } : { hallucination_count } " )
107+
108+ sorted_columns = "\n " .join (sorted (df .columns .tolist ()))
109+ logger .info (f"DataFrame columns (sorted): { sorted_columns } " )
92110
93111 return df
94112
@@ -112,7 +130,11 @@ def _initialize_instance_row(self, instance_data: dict) -> dict:
112130
113131 # Initialize all action category counts to NaN (will be overwritten if action categories data exists)
114132 for category in ACTION_CATEGORIES :
115- row [f"category_count_{ category } " ] = pd .NA
133+ row [f"c_{ category } " ] = pd .NA
134+
135+ # Initialize all hallucination category counts to NaN (will be overwritten if hallucination data exists)
136+ for category in HALLUCINATION_CATEGORIES :
137+ row [f"h_{ category } " ] = pd .NA
116138
117139 return row
118140
@@ -128,43 +150,63 @@ def _add_data_id_results(self, row: dict, data_id: str, instance_data: dict) ->
128150 self ._add_action_categories_results (row , instance_data )
129151 elif data_id == self .big_questions_data_id :
130152 self ._add_big_questions_results (row , instance_data )
153+ elif data_id == self .hallucination_data_id :
154+ self ._add_hallucination_results (row , instance_data )
131155 # Ignore other data_ids that are not handled
132156
133157 def _add_action_categories_results (self , row : dict , instance_data : dict ) -> None :
134- """Add action categories results to the row."""
135- if "result" in instance_data :
136- result_data = instance_data [ "result" ]
158+ """Add action categories counts to the row."""
159+ if "result" not in instance_data :
160+ return
137161
138- # Handle action category counts specially
139- categories = result_data .get ("categories" , [])
140- self ._add_action_category_counts (row , categories )
162+ result_data = instance_data ["result" ]
141163
142- # Add all other result data without prefix
143- for key , value in result_data .items ():
144- row [key ] = value
145-
146- def _add_big_questions_results (self , row : dict , instance_data : dict ) -> None :
147- """Add big questions results to the row."""
148- if "result" in instance_data :
149- result_data = instance_data ["result" ]
150-
151- # Add all result data without prefix
152- for key , value in result_data .items ():
153- row [key ] = value
154-
155- def _add_action_category_counts (self , row : dict , categories : list ) -> None :
156- """Add category counts to the row for action categories data."""
157164 # Initialize all category counts to 0 (this ensures missing categories are 0, not NaN)
158165 for category in ACTION_CATEGORIES :
159166 row [f"c_{ category } " ] = 0
160167
161168 # Count occurrences of each category
169+ categories = result_data .get ("categories" , [])
162170 if categories :
163171 category_counts = Counter (cat .get ("category" ) for cat in categories if cat .get ("category" ))
164172 for category , count in category_counts .items ():
165173 if category in ACTION_CATEGORIES :
166174 row [f"c_{ category } " ] = count
167175
176+ def _add_big_questions_results (self , row : dict , instance_data : dict ) -> None :
177+ """Add big questions results to the row."""
178+ if "result" not in instance_data :
179+ return
180+
181+ result_data = instance_data ["result" ]
182+
183+ # Add all result data without prefix
184+ for key , value in result_data .items ():
185+ row [key ] = value
186+
187+ def _add_hallucination_results (self , row : dict , instance_data : dict ) -> None :
188+ """Add hallucination counts to the row."""
189+ if "result" not in instance_data :
190+ return
191+
192+ result_data = instance_data ["result" ]
193+
194+ # Initialize all hallucination counts to 0 (this ensures missing categories are 0, not NaN)
195+ for category in HALLUCINATION_CATEGORIES :
196+ row [f"h_{ category } " ] = 0
197+
198+ # Count occurrences of each claim/source combination
199+ items = result_data .get ("items" , [])
200+ for item in items :
201+ claim_category = item .get ("claim_category" )
202+ source_category = item .get ("source_category" )
203+ if not claim_category or not source_category :
204+ continue
205+
206+ combination = f"{ claim_category } __{ source_category } "
207+ if combination in HALLUCINATION_CATEGORIES :
208+ row [f"h_{ combination } " ] += 1
209+
168210
169211def aggregate_results_to_dataframe (input_dir : Path ) -> pd .DataFrame :
170212 """Convenience function for backward compatibility."""
0 commit comments