ahmedtaha100 commited on
Commit
ce56286
·
verified ·
1 Parent(s): f4b993a

Upload sample_pairs.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. sample_pairs.py +59 -11
sample_pairs.py CHANGED
@@ -2,10 +2,13 @@ from __future__ import annotations
2
 
3
  import argparse
4
  import json
 
5
  import random
6
  from collections import defaultdict
7
  from pathlib import Path
8
 
 
 
9
 
10
  def classify_transformation(pair: dict) -> str:
11
  age_changed = pair.get("source_age") != pair.get("target_age")
@@ -19,6 +22,13 @@ def classify_transformation(pair: dict) -> str:
19
  return "none"
20
 
21
 
 
 
 
 
 
 
 
22
  def stratified_sample(
23
  pairs: list[dict],
24
  n_per_stratum: int,
@@ -35,19 +45,52 @@ def stratified_sample(
35
  selected: list[int] = []
36
  for stratum in ["age_only", "sex_only", "intersectional"]:
37
  pool = by_stratum[stratum]
38
- rng.shuffle(pool)
39
- n = min(n_per_stratum, len(pool))
40
- selected.extend(pool[:n])
41
- if n < n_per_stratum:
42
- print(
43
- f"Warning: only {n} pairs available for {stratum} "
44
- f"(requested {n_per_stratum})"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  )
46
 
 
 
47
  return selected
48
 
49
 
50
  def main() -> None:
 
51
  parser = argparse.ArgumentParser(
52
  description="Stratified sampling of pairs for radiologist validation"
53
  )
@@ -67,18 +110,23 @@ def main() -> None:
67
  pair["_transform_type"] = classify_transformation(pair)
68
 
69
  counts: dict[str, int] = defaultdict(int)
 
70
  for pair in sampled:
71
- counts[pair["_transform_type"]] += 1
 
 
72
 
73
  output_path = Path(args.output)
74
  output_path.parent.mkdir(parents=True, exist_ok=True)
75
  with open(output_path, "w") as f:
76
  json.dump(sampled, f, indent=2)
77
 
78
- print(f"Sampled {len(sampled)} pairs from {len(all_pairs)} total")
79
  for stratum, count in sorted(counts.items()):
80
- print(f" {stratum}: {count}")
81
- print(f"Saved to: {output_path}")
 
 
82
 
83
 
84
  if __name__ == "__main__":
 
2
 
3
  import argparse
4
  import json
5
+ import logging
6
  import random
7
  from collections import defaultdict
8
  from pathlib import Path
9
 
10
+ logger = logging.getLogger(__name__)
11
+
12
 
13
  def classify_transformation(pair: dict) -> str:
14
  age_changed = pair.get("source_age") != pair.get("target_age")
 
22
  return "none"
23
 
24
 
25
+ def _get_pathology_key(pair: dict) -> str:
26
+ labels = pair.get("pathology_labels", [])
27
+ if not labels:
28
+ return "unlabeled"
29
+ return ",".join(str(v) for v in sorted(labels))
30
+
31
+
32
  def stratified_sample(
33
  pairs: list[dict],
34
  n_per_stratum: int,
 
45
  selected: list[int] = []
46
  for stratum in ["age_only", "sex_only", "intersectional"]:
47
  pool = by_stratum[stratum]
48
+ if not pool:
49
+ logger.warning("No pairs available for stratum %s", stratum)
50
+ continue
51
+
52
+ by_pathology: dict[str, list[int]] = defaultdict(list)
53
+ for idx in pool:
54
+ key = _get_pathology_key(pairs[idx])
55
+ by_pathology[key].append(idx)
56
+
57
+ pathology_keys = sorted(by_pathology.keys())
58
+ n_categories = len(pathology_keys)
59
+ per_category = n_per_stratum // n_categories
60
+ remainder = n_per_stratum % n_categories
61
+
62
+ stratum_selected: list[int] = []
63
+ overflow_pool: list[int] = []
64
+
65
+ for k_idx, key in enumerate(pathology_keys):
66
+ candidates = by_pathology[key]
67
+ rng.shuffle(candidates)
68
+ target = per_category + (1 if k_idx < remainder else 0)
69
+ taken = min(target, len(candidates))
70
+ stratum_selected.extend(candidates[:taken])
71
+ if taken < target:
72
+ overflow_pool.extend([])
73
+ if taken < len(candidates):
74
+ overflow_pool.extend(candidates[taken:])
75
+
76
+ if len(stratum_selected) < n_per_stratum and overflow_pool:
77
+ rng.shuffle(overflow_pool)
78
+ needed = n_per_stratum - len(stratum_selected)
79
+ stratum_selected.extend(overflow_pool[:needed])
80
+
81
+ if len(stratum_selected) < n_per_stratum:
82
+ logger.warning(
83
+ "Only %d pairs available for %s (requested %d)",
84
+ len(stratum_selected), stratum, n_per_stratum,
85
  )
86
 
87
+ selected.extend(stratum_selected)
88
+
89
  return selected
90
 
91
 
92
  def main() -> None:
93
+ logging.basicConfig(level=logging.INFO)
94
  parser = argparse.ArgumentParser(
95
  description="Stratified sampling of pairs for radiologist validation"
96
  )
 
110
  pair["_transform_type"] = classify_transformation(pair)
111
 
112
  counts: dict[str, int] = defaultdict(int)
113
+ pathology_counts: dict[str, dict[str, int]] = defaultdict(lambda: defaultdict(int))
114
  for pair in sampled:
115
+ t = pair["_transform_type"]
116
+ counts[t] += 1
117
+ pathology_counts[t][_get_pathology_key(pair)] += 1
118
 
119
  output_path = Path(args.output)
120
  output_path.parent.mkdir(parents=True, exist_ok=True)
121
  with open(output_path, "w") as f:
122
  json.dump(sampled, f, indent=2)
123
 
124
+ logger.info("Sampled %d pairs from %d total", len(sampled), len(all_pairs))
125
  for stratum, count in sorted(counts.items()):
126
+ logger.info(" %s: %d", stratum, count)
127
+ for pkey, pcount in sorted(pathology_counts[stratum].items()):
128
+ logger.info(" pathology [%s]: %d", pkey, pcount)
129
+ logger.info("Saved to: %s", output_path)
130
 
131
 
132
  if __name__ == "__main__":