forked from MakazhanAlpamys/Soup
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidator.py
More file actions
148 lines (126 loc) · 4.44 KB
/
Copy pathvalidator.py
File metadata and controls
148 lines (126 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""Dataset validation and statistics."""
from __future__ import annotations
from typing import Optional
from soup_cli.data.formats import FORMAT_SIGNATURES
def validate_and_stats(data: list[dict], expected_format: Optional[str] = None) -> dict:
"""Compute stats and validate dataset."""
if not data:
return {
"total": 0,
"columns": [],
"avg_length": 0,
"min_length": 0,
"max_length": 0,
"empty_fields": 0,
"duplicates": 0,
"issues": ["Dataset is empty"],
"valid_rows": 0,
}
columns = list(data[0].keys())
# Compute text lengths (join all string values)
lengths = []
empty_count = 0
for row in data:
text = " ".join(str(v) for v in row.values() if v)
lengths.append(len(text))
for v in row.values():
if v is None:
empty_count += 1
# Detect duplicates by stringifying rows
row_strs = [str(sorted(row.items())) for row in data]
dup_count = len(row_strs) - len(set(row_strs))
# Validate format
issues = []
valid_rows = len(data)
if expected_format and expected_format in FORMAT_SIGNATURES:
required = FORMAT_SIGNATURES[expected_format]
invalid = 0
for row in data:
if not required.issubset(row.keys()):
invalid += 1
valid_rows = len(data) - invalid
if invalid > 0:
issues.append(
f"{invalid} rows missing required keys for '{expected_format}' format: {required}"
)
if dup_count > 0:
issues.append(f"{dup_count} duplicate rows found")
if empty_count > 0:
issues.append(f"{empty_count} empty fields found")
# Check for very short samples
short = sum(1 for length in lengths if length < 10)
if short > 0:
issues.append(f"{short} samples are very short (<10 chars)")
return {
"total": len(data),
"columns": columns,
"avg_length": round(sum(lengths) / len(lengths)),
"min_length": min(lengths),
"max_length": max(lengths),
"empty_fields": empty_count,
"duplicates": dup_count,
"issues": issues,
"valid_rows": valid_rows,
}
def _percentile(sorted_vals: list, pct: int) -> int:
"""Compute a percentile from a sorted list."""
if not sorted_vals:
return 0
idx = int(len(sorted_vals) * pct / 100)
idx = min(idx, len(sorted_vals) - 1)
return sorted_vals[idx]
def extended_stats(data: list[dict]) -> dict:
"""Compute extended statistics: length distribution, token counts, languages."""
if not data:
return {
"total": 0,
"lengths": [],
"token_counts": [],
"length_p10": 0,
"length_p25": 0,
"length_p50": 0,
"length_p75": 0,
"length_p90": 0,
"avg_tokens": 0,
"min_tokens": 0,
"max_tokens": 0,
"languages": {},
}
lengths = []
token_counts = []
for row in data:
text = " ".join(str(v) for v in row.values() if v)
char_len = len(text)
lengths.append(char_len)
# Approximate token count: ~4 chars per token for English
token_counts.append(max(1, char_len // 4))
sorted_lengths = sorted(lengths)
# Language detection (optional, lazy import)
languages: dict[str, int] = {}
try:
from langdetect import detect
sample_size = min(100, len(data))
for row in data[:sample_size]:
text = " ".join(str(v) for v in row.values() if v)
if len(text) > 20:
try:
lang = detect(text)
languages[lang] = languages.get(lang, 0) + 1
except Exception:
pass
except ImportError:
pass # langdetect not installed, skip
return {
"total": len(data),
"lengths": lengths,
"token_counts": token_counts,
"length_p10": _percentile(sorted_lengths, 10),
"length_p25": _percentile(sorted_lengths, 25),
"length_p50": _percentile(sorted_lengths, 50),
"length_p75": _percentile(sorted_lengths, 75),
"length_p90": _percentile(sorted_lengths, 90),
"avg_tokens": round(sum(token_counts) / len(token_counts)),
"min_tokens": min(token_counts),
"max_tokens": max(token_counts),
"languages": languages,
}