Skip to content

Commit bd7700c

Browse files
committed
exp(moviekg): updates to moviekg evaluation
1 parent 7ba8963 commit bd7700c

5 files changed

Lines changed: 192 additions & 16 deletions

File tree

experiments/moviekg/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.yaml

experiments/moviekg/eval.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
kgpipe eval -c metric_config.yaml \
2+
-m ReferenceTripleAlignmentMetricSoftEV \
3+
-m entity_count \
4+
-m incorrect_relation_direction \
5+
-m incorrect_relation_cardinality \
6+
-m incorrect_relation_range \
7+
-m incorrect_relation_domain \
8+
-m incorrect_datatype \
9+
-m incorrect_datatype_format \
10+
data/out/small/rdf_a/stage_3/result.nt

experiments/moviekg/src/moviekg/evaluation/test_sensitivity.py

Lines changed: 117 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
from dataclasses import dataclass
22
from typing import List
3-
from kgpipe.evaluation.aspects.reference import ReferenceEvaluator, ReferenceConfig
4-
3+
from kgpipe.common import KgPipe, Data, DataFormat, KG
4+
from pathlib import Path
5+
from kgpipe.common.models import KgPipePlan
6+
from kgpipe.evaluation.aspects.reference import (
7+
ReferenceEvaluator, ReferenceConfig,
8+
ER_EntityMatchMetric, ER_RelationMatchMetric,
9+
TE_ExpectedEntityLinkMetric, TE_ExpectedRelationLinkMetric
10+
)
11+
import os
512
@dataclass
613
class BinaryClassifier:
714
tp: int
@@ -21,20 +28,117 @@ class ThresholdSensitivityResult:
2128
threshold: float
2229
result: BinaryClassifier
2330

31+
benchdata = Path("/home/marvin/phd/kgpipe/experiments/moviekg/data/datasets/film_10k/")
32+
seed_path = benchdata / "split_0/kg/seed/data.nt"
33+
rdf_path = benchdata / "split_1/sources/rdf/data.nt"
34+
result_dir_path = Path(f"data/moviekg/threshold_sensitivity/")
2435

36+
# reference_evaluator = ReferenceEvaluator()
2537

26-
reference_evaluator = ReferenceEvaluator()
38+
def run_paris_pipeline(pipeline_name: str, threshold: float) -> List[ThresholdSensitivityResult]:
39+
from kgpipe_tasks.tasks import paris_entity_matching, paris_exchange
2740

28-
def paris_threshold_sensitivity(pipeline_name: str, threshold: float) -> List[ThresholdSensitivityResult]:
29-
ReferenceConfig(
30-
ENTITY_MATCH_THRESHOLD=threshold
31-
RELATION_MATCH_THRESHOLD=threshold
32-
) # TODO get config from dataset
33-
# kg = KG(path=Path(f"data/moviekg/paris/{pipeline_name}.nt"))
34-
# reference_kg = KG(path=Path("data/moviekg/paris/reference.nt"))
35-
# result = reference_evaluator.evaluate(kg, reference_kg)
36-
# return result
37-
pass
41+
pipe_result_dir_path = result_dir_path / f"{pipeline_name}"
42+
pipeline = KgPipe(
43+
name="paris pipeline",
44+
tasks=[paris_entity_matching, paris_exchange],
45+
seed=Data(path=seed_path, format=DataFormat.RDF_NTRIPLES),
46+
data_dir=pipe_result_dir_path / "tmp"
47+
)
48+
plan = pipeline.build(
49+
source=Data(path=rdf_path, format=DataFormat.RDF_NTRIPLES),
50+
result=Data(path=pipe_result_dir_path / "result.json", format=DataFormat.ER_JSON)
51+
)
52+
53+
os.makedirs(pipe_result_dir_path, exist_ok=True)
54+
55+
with open(pipe_result_dir_path / "exec-plan.json", "w") as f:
56+
f.write(plan.model_dump_json(indent=4))
57+
58+
pipeline.run()
59+
60+
def paris_er_threshold_sensitivity(pipeline_name: str, threshold: float) -> List[ThresholdSensitivityResult]:
61+
config = ReferenceConfig(
62+
name="paris config",
63+
ENTITY_MATCH_THRESHOLD=threshold,
64+
RELATION_MATCH_THRESHOLD=threshold,
65+
GT_MATCHES=benchdata / "split_1/sources/rdf/meta/verified_matches.csv",
66+
GT_MATCHES_TARGET_DATASET="split_0/kg/seed"
67+
)
68+
69+
plan = KgPipePlan.model_validate_json(open(result_dir_path / f"{pipeline_name}" / "exec-plan.json").read())
70+
71+
kg = KG(id="paris", name="paris", path=Path(f"data/moviekg/paris/{pipeline_name}.nt"), format=DataFormat.RDF_NTRIPLES, plan=plan)
72+
73+
metric_result = ER_EntityMatchMetric().compute(kg, config=config)
74+
# print(metric_result)
75+
76+
return metric_result
77+
78+
def paris_om_threshold_sensitivity(pipeline_name: str, threshold: float) -> List[ThresholdSensitivityResult]:
79+
config = ReferenceConfig(
80+
name="paris config",
81+
ENTITY_MATCH_THRESHOLD=threshold,
82+
RELATION_MATCH_THRESHOLD=threshold,
83+
GT_MATCHES=benchdata / "split_1/sources/rdf/meta/verified_matches.csv",
84+
GT_MATCHES_TARGET_DATASET="split_0/kg/seed"
85+
)
86+
87+
plan = KgPipePlan.model_validate_json(open(result_dir_path / f"{pipeline_name}" / "exec-plan.json").read())
88+
89+
kg = KG(id="paris", name="paris", path=Path(f"data/moviekg/paris/{pipeline_name}.nt"), format=DataFormat.RDF_NTRIPLES, plan=plan)
90+
91+
metric_result = ER_RelationMatchMetric().compute(kg, config=config)
92+
# print(metric_result)
93+
94+
return metric_result
95+
96+
def test_paris():
97+
# run_paris_pipeline("paris", 0.99)
98+
range_of_thresholds = [0.0, 0.001, 0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.99, 0.999, 1.0]
99+
100+
er_results = []
101+
for threshold in range_of_thresholds:
102+
result = paris_er_threshold_sensitivity("paris", threshold)
103+
er_results.append([threshold, result.normalized_score, result.details])
104+
105+
print()
106+
print("ER Results:")
107+
for r in er_results:
108+
print(r[0], r[1], r[2])
109+
110+
om_results = []
111+
for threshold in range_of_thresholds:
112+
result = paris_om_threshold_sensitivity("paris", threshold)
113+
om_results.append([threshold, result.normalized_score, result.details])
114+
115+
print("OM Results:")
116+
for r in om_results:
117+
print(r[0], r[1], r[2])
118+
119+
# def paris_threshold_sensitivity(pipeline_name: str, threshold: float) -> List[ThresholdSensitivityResult]:
120+
# result = run_paris_pipeline(pipeline_name, threshold)
121+
122+
# pipeline.run(
123+
# input=[Data(path=Path(f"data/moviekg/paris/{pipeline_name}.nt"), format=DataFormat.RDF_NTRIPLES)],
124+
# output=[Data(path=Path(f"data/moviekg/paris/{pipeline_name}.paris_csv"), format=DataFormat.PARIS_CSV)]
125+
# )
126+
127+
# config = ReferenceConfig(
128+
# name="paris config",
129+
# ENTITY_MATCH_THRESHOLD=threshold,
130+
# RELATION_MATCH_THRESHOLD=threshold
131+
# )
132+
133+
134+
135+
136+
# # TODO get config from dataset
137+
# # kg = KG(path=Path(f"data/moviekg/paris/{pipeline_name}.nt"))
138+
# # reference_kg = KG(path=Path("data/moviekg/paris/reference.nt"))
139+
# # result = reference_evaluator.evaluate(kg, reference_kg)
140+
# # return result
141+
# pass
38142

39143
def jedai_threshold_sensitivity(pipeline_name: str, threshold: float) -> List[ThresholdSensitivityResult]:
40144
pass

experiments/moviekg/src/moviekg/paper/helpers/getter.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ def ref_source_typed_entity_p(df: pd.DataFrame):
168168
res: pipeline_stage_dict = defaultdict[pipeline_name, defaultdict[stage_name, metric_value]](lambda: defaultdict[stage_name, metric_value](lambda: None))
169169
for row in df.itertuples():
170170
details = json.loads(row.details)
171-
precision = details["precision"]
171+
# print(details)
172+
precision = details.get("fn", -1)
172173
res[row.pipeline][row.stage] = precision
173174
return res
174175

@@ -177,7 +178,7 @@ def ref_source_typed_entity_r(df: pd.DataFrame):
177178
res: pipeline_stage_dict = defaultdict[pipeline_name, defaultdict[stage_name, metric_value]](lambda: defaultdict[stage_name, metric_value](lambda: None))
178179
for row in df.itertuples():
179180
details = json.loads(row.details)
180-
recall = details["recall"]
181+
recall = details.get("recall", -1)
181182
res[row.pipeline][row.stage] = recall
182183
return res
183184

experiments/moviekg/src/moviekg/paper/test_figtab.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,4 +719,64 @@ def test_new_ranking_table():
719719
# # metric_df = metric_df.reset_index(drop=True)
720720
# # metric_df = metric_df.pivot(index="pipeline", columns="metric", values="normalized")
721721
# # metric_df = metric_df.reset_index()
722-
# metric_df.to_csv(OUTPUT_ROOT / "paper/test_tab_8_new_ranking_table.csv", sep="\t")
722+
# metric_df.to_csv(OUTPUT_ROOT / "paper/test_tab_8_new_ranking_table.csv", sep="\t")
723+
724+
725+
def test_new_quality_table():
726+
727+
metric_df = load_metrics_from_file(OUTPUT_ROOT / "all_metrics.csv")
728+
metric_df["pipeline"] = metric_df["pipeline"].map(map_pipeline_name_pretty)
729+
from moviekg.paper.helpers.getter import (
730+
get_pipeline_stage_metric_dict,
731+
sta_entity_count, sta_fact_count, sta_type_count, sta_relation_count, sta_shallow_entity_count, sta_denisity, sta_duration,
732+
ref_kg_f1, ref_kg_p, ref_kg_r,
733+
ref_source_entity_f1, ref_source_entity_p, ref_source_entity_r,
734+
ref_source_typed_entity_r, ref_source_typed_entity_p,
735+
sem_disjoint_domain, sem_incorrect_relation_direction, sem_incorrect_relation_cardinality, sem_incorrect_relation_range, sem_incorrect_relation_domain, sem_incorrect_datatype, sem_incorrect_datatype_format,
736+
)
737+
738+
metrics = [
739+
sta_entity_count.__name__, sta_fact_count.__name__, sta_type_count.__name__, sta_relation_count.__name__, sta_shallow_entity_count.__name__, sta_denisity.__name__, sta_duration.__name__,
740+
ref_kg_f1.__name__, ref_kg_p.__name__,
741+
ref_kg_r.__name__, ref_source_entity_f1.__name__,
742+
ref_source_entity_p.__name__, ref_source_entity_r.__name__,
743+
ref_source_typed_entity_r.__name__, ref_source_typed_entity_p.__name__,
744+
sem_disjoint_domain.__name__, sem_incorrect_relation_direction.__name__, sem_incorrect_relation_cardinality.__name__, sem_incorrect_relation_range.__name__, sem_incorrect_relation_domain.__name__, sem_incorrect_datatype.__name__, sem_incorrect_datatype_format.__name__,
745+
]
746+
747+
psmd = get_pipeline_stage_metric_dict(metric_df, metrics)
748+
# import json
749+
# json.dump(psmd, open(OUTPUT_ROOT / "paper/test_tab_6_metrics.json", "w"), indent=4)
750+
751+
rows = []
752+
753+
round_to = 3
754+
755+
for pipeline, stage_dict in psmd.items():
756+
if pipeline in ["reference", "seed"]:
757+
continue
758+
759+
for stage, metric_dict in stage_dict.items():
760+
ec = round(metric_dict.get(sta_entity_count.__name__, -1), round_to)
761+
kg_p = round(metric_dict.get(ref_kg_p.__name__, -1), round_to)
762+
kg_r = round(metric_dict.get(ref_kg_r.__name__, -1), round_to)
763+
se_p = round(metric_dict.get(ref_source_entity_p.__name__, -1), round_to)
764+
se_r= round(metric_dict.get(ref_source_entity_r.__name__, -1), round_to)
765+
ste_p = round(metric_dict.get(ref_source_typed_entity_p.__name__, -1), round_to)
766+
ste_r = round(metric_dict.get(ref_source_typed_entity_r.__name__, -1), round_to)
767+
o_dt = round(metric_dict.get(sem_disjoint_domain.__name__, -1), round_to)
768+
o_d = round(metric_dict.get(sem_incorrect_relation_domain.__name__, -1), round_to)
769+
o_r = round(metric_dict.get(sem_incorrect_relation_range.__name__, -1), round_to)
770+
o_rd = round(metric_dict.get(sem_incorrect_relation_direction.__name__, -1), round_to)
771+
o_lt = round(metric_dict.get(sem_incorrect_datatype.__name__, -1), round_to)
772+
o_lf = round(metric_dict.get(sem_incorrect_datatype_format.__name__, -1), round_to)
773+
774+
rows.append({
775+
"pipeline": pipeline, "stage": stage,
776+
"EC": ec,
777+
"kg_p": kg_p, "kg_r": kg_r, "se_p": se_p, "se_r": se_r, "ste_p": ste_p, "ste_r": ste_r,
778+
"O_DT": o_dt, "O_D": o_d, "O_R": o_r, "O_RD": o_rd, "O_LT": o_lt, "O_LF": o_lf
779+
})
780+
781+
df = pd.DataFrame(rows)
782+
df.to_csv(OUTPUT_ROOT / "paper/test_tab_9_new_quality_table.csv", sep="\t")

0 commit comments

Comments
 (0)