| import pandas as pd |
| from utils.db import get_questions_df |
|
|
|
|
| def topic_frequency_by_year(db_path="data/exam.db", exam=None): |
| df = get_questions_df(db_path) |
| if exam: |
| df = df[df["exam"] == exam] |
| freq = df.groupby(["topic", "micro_topic", "year"]).size().unstack(fill_value=0) |
| return freq |
|
|
|
|
| def find_hot_cold_topics(db_path="data/exam.db", recent_years=3, current_year=None): |
| df = get_questions_df(db_path) |
| if current_year is None: |
| current_year = df["year"].max() |
|
|
| recent_cutoff = current_year - recent_years + 1 |
|
|
| topic_last_year = df.groupby(["topic", "micro_topic"])["year"].max() |
| topic_recent_count = ( |
| df[df["year"] >= recent_cutoff] |
| .groupby(["topic", "micro_topic"]) |
| .size() |
| ) |
|
|
| hot = topic_recent_count.sort_values(ascending=False) |
| hot_topics = [(idx, idx[1], count) for idx, count in hot.items()] |
|
|
| cold_topics = [] |
| for idx, last_year in topic_last_year.items(): |
| if last_year < recent_cutoff: |
| gap = current_year - last_year |
| cold_topics.append((idx, idx[1], gap)) |
| cold_topics.sort(key=lambda x: x[2], reverse=True) |
|
|
| return hot_topics, cold_topics |
|
|
|
|
| def detect_cycles(db_path="data/exam.db", min_occurrences=4, exclude_years=None): |
| df = get_questions_df(db_path) |
| if exclude_years: |
| df = df[~df["year"].isin(exclude_years)] |
| results = [] |
|
|
| for (topic, micro_topic), group in df.groupby(["topic", "micro_topic"]): |
| years = sorted(group["year"].unique()) |
| if len(years) < min_occurrences: |
| continue |
|
|
| gaps = [years[i + 1] - years[i] for i in range(len(years) - 1)] |
| if not gaps: |
| continue |
|
|
| avg_gap = sum(gaps) / len(gaps) |
| variance = sum((g - avg_gap) ** 2 for g in gaps) / len(gaps) |
|
|
| if variance <= 1.5: |
| results.append({ |
| "topic": topic, |
| "micro_topic": micro_topic, |
| "estimated_cycle_years": round(avg_gap), |
| "appearances": years, |
| "avg_gap": round(avg_gap, 1), |
| "consistency": round(1 - (variance / (avg_gap ** 2 + 0.01)), 2), |
| }) |
|
|
| results.sort(key=lambda x: x["consistency"], reverse=True) |
| return results |
|
|