1:- module(ap_calibration, [evaluate_csv/2, print_evaluation/1]).

Evaluasi historis sederhana.

CSV harus berisi fitur model dan actual_protest (0/1). Modul ini MENGUJI model, bukan melatih ulang bobot. Ini sengaja agar v0.1 tidak berpura-pura terkalibrasi.

    9:- use_module(library(csv)).   10:- use_module(library(lists)).   11:- use_module(library(apply)).   12:- use_module(library(pairs)).   13:- use_module(ap_defaults).   14:- use_module(ap_model).   15:- use_module(ap_validation).   16
   17evaluate_csv(File, Summary) :-
   18    csv_read_file(File, Rows, [functor(row), strip(true)]),
   19    Rows = [Header|Data],
   20    Header =.. [_|Names0], maplist(to_atom, Names0, Names),
   21    findall(Pred-Actual,
   22            ( member(Row, Data),
   23              Row =.. [_|Values],
   24              pairs_keys_values(Pairs, Names, Values),
   25              row_scenario(Pairs, S, Actual),
   26              ap_model:score(S, R),
   27              Pred is R.likelihood/100.0
   28            ), PairsPA),
   29    summarize(PairsPA, Summary).
   30
   31row_scenario(Pairs, S, Actual) :-
   32    ap_defaults:default_scenario(D),
   33    model_feature_keys(Keys),
   34    foldl(apply_pair(Pairs), Keys, D, S),
   35    ( memberchk(actual_protest-A0, Pairs), ap_validation:safe_number(A0, A1), A1 >= 0.5 -> Actual=1 ; Actual=0 ).
   36
   37apply_pair(Pairs, Key, S0, S) :-
   38    ( memberchk(Key-Raw, Pairs), ap_validation:safe_number(Raw, N) -> put_dict(Key, S0, N, S)
   39    ; S = S0
   40    ).
   41
   42model_feature_keys([grievance,trigger,salience,online,coalition,organization,
   43    economic_stress,institutional_distrust,incident_shock,recent_precedent,
   44    media_attention,public_support,regional_relevance,govt_communication,
   45    govt_responsiveness,organizer_control,intervention_pressure,evidence_quality]).
   46
   47to_atom(X, A) :- atom(X), !, A=X.
   48to_atom(X, A) :- string(X), !, atom_string(A, X).
   49to_atom(X, A) :- term_to_atom(X, A).
   50
   51summarize([], _{events:0, accuracy:null, brier:null, warning:'tidak ada data'}).
   52summarize(Pairs, Summary) :-
   53    length(Pairs, N),
   54    findall(C, (member(P-A,Pairs), predicted_class(P,PC), (PC=:=A -> C=1 ; C=0)), Cs),
   55    sum_list(Cs, Correct), Accuracy is Correct/N,
   56    findall(B, (member(P-A,Pairs), B is (P-A)*(P-A)), Bs), sum_list(Bs, BSum), Brier is BSum/N,
   57    Summary = _{events:N, accuracy:Accuracy, brier:Brier,
   58                warning:'evaluasi in-sample hanya bermakna bila CSV benar-benar historis dan fitur ditentukan tanpa melihat outcome'}.
   59
   60predicted_class(P, 1) :- P >= 0.5, !.
   61predicted_class(_, 0).
   62
   63print_evaluation(S) :-
   64    format('Events  : ~w~n', [S.events]),
   65    format('Accuracy: ~w~n', [S.accuracy]),
   66    format('Brier   : ~w~n', [S.brier]),
   67    format('Catatan : ~w~n', [S.warning])