summaryrefslogtreecommitdiff
path: root/split_dataset.py
diff options
context:
space:
mode:
Diffstat (limited to 'split_dataset.py')
-rw-r--r--split_dataset.py66
1 files changed, 52 insertions, 14 deletions
diff --git a/split_dataset.py b/split_dataset.py
index 9ac7bbf..a161cc1 100644
--- a/split_dataset.py
+++ b/split_dataset.py
@@ -7,10 +7,12 @@ def split_dataset(
7 input_filepath: str, 7 input_filepath: str,
8 train_filepath: str = "train.jsonl", 8 train_filepath: str = "train.jsonl",
9 validation_filepath: str = "validation.jsonl", 9 validation_filepath: str = "validation.jsonl",
10 split_ratio: float = 0.95 10 split_ratio: float = 0.95,
11 balance_ratio: float = 1.0
11): 12):
12 """ 13 """
13 Reads a .jsonl file, shuffles it, and splits it into training and validation files. 14 Reads a .jsonl file, balances the positive/negative examples, shuffles,
15 and splits it into training and validation files.
14 """ 16 """
15 print(f"Loading data from {input_filepath}...") 17 print(f"Loading data from {input_filepath}...")
16 try: 18 try:
@@ -20,23 +22,51 @@ def split_dataset(
20 print(f"Error: Input file not found at {input_filepath}", file=sys.stderr) 22 print(f"Error: Input file not found at {input_filepath}", file=sys.stderr)
21 sys.exit(1) 23 sys.exit(1)
22 24
23 # Shuffle the dataset to ensure random distribution 25 # 1. Separate into positive and negative examples
24 print("Shuffling data...") 26 positive_examples = []
25 random.shuffle(lines) 27 negative_examples = []
28 for line in lines:
29 try:
30 entry = json.loads(line)
31 if entry.get("target", "").strip():
32 positive_examples.append(line)
33 else:
34 negative_examples.append(line)
35 except json.JSONDecodeError:
36 print(f"Warning: Skipping malformed JSON line: {line.strip()}", file=sys.stderr)
26 37
27 # Determine the split point 38 print(f"Found {len(positive_examples)} positive examples and {len(negative_examples)} negative examples.")
28 split_index = int(len(lines) * split_ratio)
29 39
30 # Split the data 40 # 2. Shuffle both lists independently
31 train_lines = lines[:split_index] 41 random.shuffle(positive_examples)
32 validation_lines = lines[split_index:] 42 random.shuffle(negative_examples)
43
44 # 3. Balance the dataset based on the ratio
45 num_positives = len(positive_examples)
46 num_negatives_to_keep = int(num_positives * balance_ratio)
47
48 if len(negative_examples) < num_negatives_to_keep:
49 print(f"Warning: Not enough negative examples to meet a {balance_ratio}:1 ratio. "
50 f"Using all {len(negative_examples)} negative examples.", file=sys.stderr)
51 num_negatives_to_keep = len(negative_examples)
52
53 print(f"Balancing dataset with {num_positives} positive and {num_negatives_to_keep} negative examples.")
54
55 balanced_lines = positive_examples + negative_examples[:num_negatives_to_keep]
56
57 # 4. Final shuffle to mix positive and negative examples
58 print("Shuffling final balanced dataset...")
59 random.shuffle(balanced_lines)
60
61 # 5. Determine the split point and write files
62 split_index = int(len(balanced_lines) * split_ratio)
63 train_lines = balanced_lines[:split_index]
64 validation_lines = balanced_lines[split_index:]
33 65
34 # Write the training file
35 print(f"Writing {len(train_lines)} lines to {train_filepath}...") 66 print(f"Writing {len(train_lines)} lines to {train_filepath}...")
36 with open(train_filepath, 'w', encoding='utf-8') as f: 67 with open(train_filepath, 'w', encoding='utf-8') as f:
37 f.writelines(train_lines) 68 f.writelines(train_lines)
38 69
39 # Write the validation file
40 print(f"Writing {len(validation_lines)} lines to {validation_filepath}...") 70 print(f"Writing {len(validation_lines)} lines to {validation_filepath}...")
41 with open(validation_filepath, 'w', encoding='utf-8') as f: 71 with open(validation_filepath, 'w', encoding='utf-8') as f:
42 f.writelines(validation_lines) 72 f.writelines(validation_lines)
@@ -44,7 +74,9 @@ def split_dataset(
44 print("\nSplitting complete.") 74 print("\nSplitting complete.")
45 75
46if __name__ == "__main__": 76if __name__ == "__main__":
47 parser = argparse.ArgumentParser(description="Split a .jsonl dataset into training and validation sets.") 77 parser = argparse.ArgumentParser(
78 description="Balance and split a .jsonl dataset into training and validation sets."
79 )
48 parser.add_argument("input_file", type=str, help="Path to the input .jsonl file.") 80 parser.add_argument("input_file", type=str, help="Path to the input .jsonl file.")
49 parser.add_argument( 81 parser.add_argument(
50 "--split", 82 "--split",
@@ -52,6 +84,12 @@ if __name__ == "__main__":
52 default=0.95, 84 default=0.95,
53 help="Ratio for the training set split (e.g., 0.95 for a 95/5 split). Default is 0.95." 85 help="Ratio for the training set split (e.g., 0.95 for a 95/5 split). Default is 0.95."
54 ) 86 )
87 parser.add_argument(
88 "--ratio",
89 type=float,
90 default=1.0,
91 help="Ratio of negative to positive examples (e.g., 1.0 for 1:1, 2.0 for 2:1). Default is 1.0."
92 )
55 93
56 args = parser.parse_args() 94 args = parser.parse_args()
57 95
@@ -59,4 +97,4 @@ if __name__ == "__main__":
59 print("Error: Split ratio must be between 0 and 1.", file=sys.stderr) 97 print("Error: Split ratio must be between 0 and 1.", file=sys.stderr)
60 sys.exit(1) 98 sys.exit(1)
61 99
62 split_dataset(args.input_file, split_ratio=args.split) \ No newline at end of file 100 split_dataset(args.input_file, split_ratio=args.split, balance_ratio=args.ratio) \ No newline at end of file