Mercurial > repos > bgruening > cleanlab
changeset 0:462b5bc27acd draft default tip
planemo upload for repository https://github.com/cleanlab/cleanlab commit ac4753a61ee908bc2a5953b6c6d38d2bbbacc6c0
| author | bgruening |
|---|---|
| date | Wed, 28 May 2025 11:30:50 +0000 |
| parents | |
| children | |
| files | cleanlab_issue_handler.py cleanlab_issue_handler.xml test-data/breast_cancer.csv test-data/breast_cancer.tsv test-data/reg_1027_ESL.csv |
| diffstat | 5 files changed, 1560 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cleanlab_issue_handler.py Wed May 28 11:30:50 2025 +0000 @@ -0,0 +1,187 @@ +import argparse + +import numpy as np +import pandas as pd +from cleanlab.datalab.datalab import Datalab +from cleanlab.regression.rank import get_label_quality_scores +from sklearn.linear_model import LinearRegression +from sklearn.model_selection import cross_val_predict, KFold, StratifiedKFold +from xgboost import XGBClassifier + +# ------------------- +# Issue Handler +# ------------------- + + +class IssueHandler: + def __init__(self, dataset, task, target_column, n_splits=3, quality_threshold=0.2): + self.dataset = dataset + self.task = task + self.target_column = target_column + self.n_splits = n_splits + self.quality_threshold = quality_threshold + self.issues = None + self.features = self.dataset.drop(target_column, axis=1).columns.tolist() + self.issue_summary = None + self.pred_probs = None + + def report_issues(self): + X = self.dataset.drop(self.target_column, axis=1) + y = self.dataset[self.target_column] + + # Ensure compatibility with Galaxy + X = X.to_numpy() if hasattr(X, 'to_numpy') else np.asarray(X) + y = y.to_numpy() if hasattr(y, 'to_numpy') else np.asarray(y) + + if self.task == 'classification': + model = XGBClassifier(use_label_encoder=False, eval_metric='logloss', random_state=42) + cv = StratifiedKFold(n_splits=self.n_splits, shuffle=True, random_state=42) + self.pred_probs = cross_val_predict(model, X, y, cv=cv, method='predict_proba') + + lab = Datalab(self.dataset, label_name=self.target_column) + lab.find_issues(pred_probs=self.pred_probs) + self.issues = lab.get_issues() + self.issue_summary = lab.get_issue_summary() + print(self.issue_summary) + + elif self.task == 'regression': + model = LinearRegression() + cv = KFold(n_splits=self.n_splits, shuffle=True, random_state=42) + pred_y = cross_val_predict(model, X, y, cv=cv, method='predict') + scores = get_label_quality_scores(y, pred_y, method='residual') + is_low_quality = scores < self.quality_threshold + self.issues = pd.DataFrame({ + 'label_quality': scores, + 'is_low_quality': is_low_quality + }) + self.issue_summary = { + 'quality_threshold': self.quality_threshold, + 'num_low_quality': int(is_low_quality.sum()), + 'mean_label_quality': float(np.mean(scores)), + 'median_label_quality': float(np.median(scores)), + 'min_label_quality': float(np.min(scores)), + 'max_label_quality': float(np.max(scores)), + } + print("Regression Issue Summary:") + for k, v in self.issue_summary.items(): + print(f"{k.replace('_', ' ').capitalize()}: {v:.4f}" if isinstance(v, float) else f"{k.replace('_', ' ').capitalize()}: {v}") + + return self.dataset.copy(), self.issues.copy(), self.issue_summary + + def clean_selected_issues(self, method='remove', label_issues=True, outliers=True, near_duplicates=True, non_iid=True): + if self.issues is None: + raise RuntimeError("Must run report_issues() before cleaning.") + + if self.task == 'regression': + clean_mask = self.issues['is_low_quality'].fillna(False) + else: + clean_mask = pd.Series([False] * len(self.dataset)) + for issue_type, use_flag in [ + ('is_label_issue', label_issues), + ('is_outlier_issue', outliers), + ('is_near_duplicate_issue', near_duplicates), + ('is_non_iid_issue', non_iid) + ]: + if use_flag and issue_type in self.issues.columns: + clean_mask |= self.issues[issue_type].fillna(False) + + if method == 'remove': + return self.dataset[~clean_mask].copy() + + elif method == 'replace' and self.task == 'classification': + most_likely = np.argmax(self.pred_probs, axis=1) + fixed = self.dataset.copy() + to_fix = self.issues['is_label_issue'] & label_issues + fixed.loc[to_fix, self.target_column] = most_likely[to_fix] + return fixed + + elif method == 'replace' and self.task == 'regression': + raise NotImplementedError("Replace method not implemented for regression label correction.") + + else: + raise ValueError("Invalid method or unsupported combination.") + +# ------------------- +# Main CLI Entry +# ------------------- + + +def main(): + parser = argparse.ArgumentParser(description="Cleanlab Issue Handler CLI") + parser.add_argument("--input_file", nargs=2, required=True, metavar=('FILE', 'EXT'), help="Input file path and its extension") + parser.add_argument("--task", required=True, choices=["classification", "regression"], help="Type of ML task") + parser.add_argument("--target_column", default="target", help="Name of the target column") + parser.add_argument("--method", default="remove", choices=["remove", "replace"], help="Cleaning method") + parser.add_argument("--summary", action="store_true", help="Print and save issue summary only, no cleaning") + parser.add_argument("--no-label-issues", action="store_true", help="Exclude label issues from cleaning") + parser.add_argument("--no-outliers", action="store_true", help="Exclude outlier issues from cleaning") + parser.add_argument("--no-near-duplicates", action="store_true", help="Exclude near-duplicate issues from cleaning") + parser.add_argument("--no-non-iid", action="store_true", help="Exclude non-i.i.d. issues from cleaning") + parser.add_argument('--quality-threshold', type=float, default=0.2, help='Threshold for low-quality labels (regression only)') + + args = parser.parse_args() + + # Load dataset based on file extension + file_path, file_ext = args.input_file + file_ext = file_ext.lower() + + print(f"Loading dataset from: {file_path} with extension: {file_ext}") + + if file_ext == "csv": + df = pd.read_csv(file_path) + elif file_ext in ["tsv", "tabular"]: + df = pd.read_csv(file_path, sep="\t") + else: + raise ValueError(f"Unsupported file format: {file_ext}") + + # Run IssueHandler + handler = IssueHandler(dataset=df, + task=args.task, + target_column=args.target_column, + quality_threshold=args.quality_threshold) + _, issues, summary = handler.report_issues() + + # Save summary + if summary is not None: + with open("summary.txt", "w") as f: + if args.task == "regression": + f.write("Regression Issue Summary:\n") + for k, v in summary.items(): + text = f"{k.replace('_', ' ').capitalize()}: {v:.4f}" if isinstance(v, float) else f"{k.replace('_', ' ').capitalize()}: {v}" + f.write(text + "\n") + else: + f.write(str(summary)) + print("Issue summary saved to: summary.txt") + + if args.summary: + return + + # Clean selected issues + cleaned_df = handler.clean_selected_issues( + method=args.method, + label_issues=not args.no_label_issues, + outliers=not args.no_outliers, + near_duplicates=not args.no_near_duplicates, + non_iid=not args.no_non_iid + ) + + print(f"Cleaned dataset shape: {cleaned_df.shape}") + print(f"Original dataset shape: {df.shape}") + + output_filename = "cleaned_data" + if file_ext == "csv": + cleaned_df.to_csv(output_filename, index=False) + elif file_ext in ["tsv", "tabular"]: + cleaned_df.to_csv(output_filename, sep="\t", index=False) + else: + raise ValueError(f"Unsupported output format: {file_ext}") + + print(f"Cleaned dataset saved to: {output_filename}") + +# ------------------- +# Entry point +# ------------------- + + +if __name__ == "__main__": + main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cleanlab_issue_handler.xml Wed May 28 11:30:50 2025 +0000 @@ -0,0 +1,310 @@ +<tool id="cleanlab_issue_handler" name="Cleanlab Issue Handler" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="23.0"> + <description>Detect and optionally clean data issues using Cleanlab</description> + <macros> + <token name="@TOOL_VERSION@">2.7.1</token> + <token name="@VERSION_SUFFIX@">1.0</token> + </macros> + + <requirements> + <requirement type="package" version="2.7.1">cleanlab</requirement> + <requirement type="package" version="3.6.0">datasets</requirement> + <requirement type="package" version="3.0.0">xgboost</requirement> + </requirements> + + <command detect_errors="exit_code"><![CDATA[ + python '${__tool_directory__}/cleanlab_issue_handler.py' + --input_file '$input_file' '$input_file.ext' + --target_column '$target_column' + --task "$task_block.task" + --method "$task_block.method" + #if $summary_only: + --summary + #end if + #if str($task_block.task) == "classification": + $task_block.label_issues + $task_block.outliers + $task_block.near_duplicates + $task_block.non_iid + #elif str($task_block.task) == "regression": + --quality-threshold "$task_block.quality_threshold" + #end if + ]]></command> + + <inputs> + <param name="input_file" type="data" format="csv,tsv,tabular" label="Input data file"/> + <param name="target_column" type="text" optional="false" label="Target column name" value="target" help="Name of the target column in the input data file. Default is 'target'."/> + <param name="summary_only" type="boolean" label="Only generate summary report?" checked="false"/> + + <conditional name="task_block"> + <param name="task" type="select" label="Task type"> + <option value="classification">Classification</option> + <option value="regression">Regression</option> + </param> + + <when value="classification"> + <param name="method" type="select" label="Cleaning method"> + <option value="remove">Remove problematic rows</option> + <option value="replace">Replace problematic labels (classification only)</option> + </param> + <param name="label_issues" type="boolean" truevalue="" falsevalue="--no-label-issues" label="Remove/Replace label issues" checked="true"/> + <param name="outliers" type="boolean" truevalue="" falsevalue="--no-outliers" label="Remove/Replace outlier issues" checked="true"/> + <param name="near_duplicates" type="boolean" truevalue="" falsevalue="--no-near-duplicates" label="Remove/Replace near-duplicate issues" checked="true"/> + <param name="non_iid" type="boolean" truevalue="" falsevalue="--no-non-iid" label="Remove/Replace non-IID issues" checked="true"/> + </when> + + <when value="regression"> + <param name="method" type="select" label="Cleaning method"> + <option value="remove">Remove problematic rows</option> + <!-- No "replace" option for regression --> + </param> + <param name="quality_threshold" type="float" label="Quality threshold" value="0.2" min="0.0" max="1.0" help="Threshold for low-quality labels. Default is 0.2."/> + <!-- No issue type parameters shown --> + </when> + </conditional> + </inputs> + + <outputs> + <data name="report_file" from_work_dir="summary.txt" format="txt" label="Issue Report"/> + + <data name="output_file" from_work_dir="cleaned_data" format_source="input_file" label="cleaned_${input_file.name}"> + <filter>not summary_only</filter> + </data> + </outputs> + + <tests> + <!-- Test1: only summary --> + <test expect_num_outputs="1"> + <param name="input_file" value="breast_cancer.csv" /> + <param name="target_column" value="target" /> + <param name="summary_only" value="true" /> + + <conditional name="task_block"> + <param name="task" value="classification" /> + <param name="method" value="remove" /> + <param name="label_issues" value="true" /> + <param name="outliers" value="true" /> + <param name="near_duplicates" value="true" /> + <param name="non_iid" value="true" /> + </conditional> + + <output name="report_file"> + <assert_contents> + <has_text_matching expression="issue_type\s+score\s+num_issues"/> + <has_text_matching expression="label\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + <has_text_matching expression="outlier\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + <has_text_matching expression="non_iid\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + </assert_contents> + </output> + </test> + + <!-- Test2: summary and cleaned all --> + <test expect_num_outputs="2"> + <param name="input_file" value="breast_cancer.csv" /> + <param name="target_column" value="target" /> + <param name="summary_only" value="false" /> + + <conditional name="task_block"> + <param name="task" value="classification" /> + <param name="method" value="remove" /> + <param name="label_issues" value="true" /> + <param name="outliers" value="true" /> + <param name="near_duplicates" value="true" /> + <param name="non_iid" value="true" /> + </conditional> + + <output name="report_file"> + <assert_contents> + <has_text_matching expression="issue_type\s+score\s+num_issues"/> + <has_text_matching expression="label\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + <has_text_matching expression="outlier\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + <has_text_matching expression="non_iid\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + </assert_contents> + </output> + + <output name="output_file"> + <assert_contents> + <has_text_matching expression=".*target.*"/> + <has_text_matching expression="^.*,.+,.+"/> + </assert_contents> + </output> + </test> + + <!-- Test3: summary and cleaned label issues only --> + <test expect_num_outputs="2"> + <param name="input_file" value="breast_cancer.csv" /> + <param name="target_column" value="target" /> + <param name="summary_only" value="false" /> + + <conditional name="task_block"> + <param name="task" value="classification" /> + <param name="method" value="remove" /> + <param name="label_issues" value="true" /> + <param name="outliers" value="false" /> + <param name="near_duplicates" value="false" /> + <param name="non_iid" value="false" /> + </conditional> + + <output name="report_file"> + <assert_contents> + <has_text_matching expression="label\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + </assert_contents> + </output> + + <output name="output_file"> + <assert_contents> + <has_text_matching expression=".*target.*"/> + <has_text_matching expression="^.*,.+,.+"/> + </assert_contents> + </output> + </test> + + <!-- Test4: summary and cleaned outliers only --> + <test expect_num_outputs="2"> + <param name="input_file" value="breast_cancer.csv" /> + <param name="target_column" value="target" /> + <param name="summary_only" value="false" /> + + <conditional name="task_block"> + <param name="task" value="classification" /> + <param name="method" value="remove" /> + <param name="label_issues" value="false" /> + <param name="outliers" value="true" /> + <param name="near_duplicates" value="false" /> + <param name="non_iid" value="false" /> + </conditional> + + <output name="report_file"> + <assert_contents> + <has_text_matching expression="outlier\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + </assert_contents> + </output> + + <output name="output_file"> + <assert_contents> + <has_text_matching expression=".*target.*"/> + <has_text_matching expression="^.*,.+,.+"/> + </assert_contents> + </output> + </test> + + <!-- Test5: summary and clean all for tsv --> + <test expect_num_outputs="2"> + <param name="input_file" value="breast_cancer.tsv" /> + <param name="target_column" value="target" /> + <param name="summary_only" value="false" /> + + <conditional name="task_block"> + <param name="task" value="classification" /> + <param name="method" value="remove" /> + <param name="label_issues" value="true" /> + <param name="outliers" value="true" /> + <param name="near_duplicates" value="true" /> + <param name="non_iid" value="true" /> + </conditional> + + <output name="report_file"> + <assert_contents> + <has_text_matching expression="issue_type\s+score\s+num_issues"/> + <has_text_matching expression="label\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + <has_text_matching expression="outlier\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + <has_text_matching expression="non_iid\s+(0(\.\d+)?|1(\.0+)?)\s+\d+"/> + </assert_contents> + </output> + + <output name="output_file"> + <assert_contents> + <has_text_matching expression=".*target.*"/> + <has_text_matching expression="^.*\t.+\t.+"/> + </assert_contents> + </output> + </test> + + <!-- Test6: regression with summary and cleaned output --> + <test expect_num_outputs="2"> + <param name="input_file" value="reg_1027_ESL.csv" /> + <param name="target_column" value="target" /> + <param name="summary_only" value="false" /> + + <conditional name="task_block"> + <param name="task" value="regression" /> + <param name="method" value="remove" /> + </conditional> + + <output name="report_file"> + <assert_contents> + <has_text text="Regression Issue Summary:"/> + <has_text_matching expression="Num low quality:"/> + <has_text_matching expression="Mean label quality:"/> + </assert_contents> + </output> + + <output name="output_file"> + <assert_contents> + <has_text_matching expression=".*target.*"/> + <has_text_matching expression="^.*,.+,.+"/> + </assert_contents> + </output> + </test> +</tests> + + <help>< Python library. It supports **classification** and **regression** tasks and helps improve dataset quality by detecting label errors, outliers, near-duplicate entries, and non-IID samples. + +The tool internally fits a cross-validated model (e.g., via XGBoost) to estimate label quality and identify problematic samples. These issues can be summarized in a report, and optionally addressed via removal or correction (depending on task and selected method). + +-------------------- + +**Detected Issue Types (with technical examples)** + +- **Label Issues** + These are samples whose label in the dataset is likely incorrect. + **Example:** In a medical classification dataset, a patient's record is labeled as "benign," but its feature pattern is highly similar to correctly labeled "malignant" cases. + + +- **Outliers** + Points that are statistically distant from the rest of the dataset. + **Example**: An entry with unusually high or low feature values (e.g., several standard deviations away from the mean). + +- **Near-Duplicates** + Highly similar or repeated samples. + **Example**: Two rows with nearly identical features and labels — possibly a duplication or copy artifact. + +- **Non-IID Samples** *(classification only)* + Samples that violate the assumption of independent and identically distributed data. + **Example**: A subset from a different population source (e.g., a different hospital or device) introducing distributional shift. + +-------------------- + +**Parameters** + +- **Input file**: Tabular file (CSV/TSV) with a `target` column. +- **Task type**: `classification` or `regression`. +- **Method**: `remove` (delete problematic rows) or `replace` (correct labels — classification only). +- **Only report issues**: If checked, input data is unchanged; only a summary report is produced. +- **Issue types**: Choose which issues to detect and handle. +- **Quality threshold** *(regression only)*: A float between 0.0 and 1.0 that determines how aggressively the tool flags low-quality labels in regression. Labels with quality scores below this threshold will be removed. + +-------------------- + +**Outputs** + +- **summary.txt**: Report listing each issue type, confidence score, and number of affected rows. +- **cleaned_data**: Cleaned dataset (CSV/TSV), only produced if "Only report issues" is unchecked. + + ]]></help> + + <citations> + <citation type="bibtex"> +@inproceedings{northcutt2021confident, + title={Confident learning: Estimating uncertainty in dataset labels}, + author={Northcutt, Curtis G and Jiang, Lu and Chuang, Alex}, + booktitle={Journal of Artificial Intelligence Research}, + year={2021}, + volume={70}, + pages={1373--1411} +} + </citation> + </citations> +</tool>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/breast_cancer.csv Wed May 28 11:30:50 2025 +0000 @@ -0,0 +1,287 @@ +age,menopause,tumor-size,inv-nodes,node-caps,deg-malig,breast,breast-quad,irradiat,target +2,2,2,0,2,3,1,3,0,1 +3,0,2,0,1,1,1,1,0,0 +3,0,6,0,1,2,0,2,0,1 +2,2,6,0,2,3,1,2,1,0 +2,2,5,4,2,2,0,5,0,1 +3,2,4,4,1,2,1,3,1,0 +3,0,7,0,1,3,0,3,0,0 +2,2,1,0,1,2,0,3,0,0 +2,2,0,0,1,2,1,4,0,0 +2,0,7,2,2,2,1,3,1,0 +3,2,4,0,1,2,0,2,0,0 +4,0,2,0,1,2,1,3,0,0 +3,0,5,0,1,1,1,1,0,0 +3,0,4,0,1,2,1,3,0,0 +2,2,4,0,1,2,0,2,1,1 +1,2,3,0,1,3,0,1,0,0 +3,2,1,4,1,1,1,3,0,0 +4,0,2,0,1,2,1,3,0,0 +3,2,7,0,1,2,0,3,0,0 +3,0,3,0,1,3,0,3,0,0 +3,1,3,0,0,1,0,2,0,1 +4,0,7,4,1,2,1,3,1,0 +3,0,2,0,1,2,1,2,0,0 +2,2,1,0,1,1,1,3,0,0 +1,2,2,5,2,3,0,2,1,1 +3,0,3,4,2,2,1,3,0,0 +3,0,1,0,1,2,1,2,0,0 +2,2,1,0,1,1,1,3,0,0 +4,0,5,4,2,3,0,2,0,0 +2,2,2,2,2,3,0,2,0,1 +4,0,5,0,1,3,1,1,0,1 +4,0,4,4,0,1,1,2,1,0 +3,0,4,0,1,3,0,5,0,0 +3,0,3,0,1,3,1,3,0,0 +2,2,5,0,1,1,0,2,1,1 +1,2,2,0,1,1,0,2,0,0 +2,2,1,0,1,2,1,3,0,0 +4,0,8,5,2,3,0,1,0,0 +2,0,3,0,1,3,0,2,0,0 +2,2,1,0,1,1,1,4,0,0 +1,2,6,0,1,3,0,2,0,1 +2,2,6,6,2,2,1,5,1,0 +4,0,4,0,1,2,1,2,0,0 +3,0,3,4,2,3,1,5,0,1 +1,2,2,0,1,1,0,2,0,0 +3,2,5,0,1,3,0,5,0,1 +4,0,1,0,1,2,1,3,1,0 +2,2,6,0,2,3,1,3,1,0 +3,2,10,0,2,2,1,3,1,0 +3,0,7,0,1,3,1,3,0,0 +5,0,2,6,0,1,0,2,1,1 +3,1,5,0,1,3,1,3,0,0 +2,2,0,0,1,3,0,1,0,0 +5,0,7,0,1,1,1,5,0,0 +2,2,4,0,0,2,0,4,1,0 +3,0,4,2,2,3,1,3,0,0 +3,2,3,0,1,1,0,2,0,0 +3,0,6,2,1,3,0,2,0,0 +3,0,10,0,1,1,1,5,0,0 +1,2,0,0,1,2,1,1,0,1 +3,0,7,5,2,3,0,2,1,1 +2,2,5,0,1,2,1,5,1,0 +2,0,3,0,1,3,0,3,0,0 +2,2,5,2,2,3,0,2,0,1 +2,0,3,0,1,2,1,3,0,1 +3,0,2,0,1,1,1,1,0,0 +1,2,4,0,1,2,1,2,0,0 +4,0,2,0,1,2,0,2,0,0 +3,2,10,6,2,2,1,3,0,1 +1,2,1,0,1,1,1,2,0,0 +3,2,4,4,2,3,0,2,1,1 +4,0,4,4,0,1,1,3,1,0 +4,0,1,0,1,1,1,2,0,0 +3,0,5,5,2,3,0,4,0,1 +1,2,4,5,2,3,0,4,1,1 +3,0,1,0,1,1,0,2,0,0 +3,2,2,0,1,1,0,2,0,0 +2,2,4,0,1,2,1,1,0,0 +2,2,4,0,1,3,0,5,0,1 +4,0,5,5,2,2,1,5,0,0 +3,1,2,0,1,2,0,2,0,0 +2,2,4,0,1,2,1,2,0,0 +2,2,5,0,1,1,1,3,0,0 +4,0,2,0,1,2,0,3,1,0 +1,2,0,0,1,2,1,1,0,0 +3,0,6,0,1,3,0,3,0,0 +2,2,7,0,1,1,1,3,0,0 +1,2,4,5,2,2,1,3,1,0 +3,0,3,0,1,1,1,2,0,0 +3,0,5,0,1,1,0,3,0,0 +4,0,3,0,1,1,1,3,0,1 +1,2,5,4,1,3,1,3,1,1 +3,1,3,0,0,1,0,3,0,1 +3,2,1,0,1,2,1,3,0,0 +3,0,3,0,1,2,1,3,0,0 +2,2,8,0,1,2,0,2,1,0 +1,2,7,0,1,1,0,3,0,1 +3,2,1,0,1,1,0,2,0,0 +4,0,5,0,1,3,1,3,1,1 +2,2,6,0,1,1,1,3,0,1 +2,2,3,4,2,2,0,2,1,1 +3,2,2,0,1,2,0,2,0,1 +3,0,5,0,1,3,1,2,0,0 +4,0,3,0,1,2,0,3,0,0 +2,2,3,0,1,1,0,4,0,0 +4,0,5,4,2,2,0,1,1,1 +4,0,3,4,1,2,0,2,1,1 +3,2,4,0,1,2,0,5,0,1 +3,0,5,0,1,1,1,5,0,0 +2,2,3,0,1,2,0,4,0,0 +4,0,2,0,1,1,1,3,0,0 +4,0,5,0,1,2,0,2,1,0 +1,2,5,0,1,2,0,3,0,0 +1,2,7,4,1,3,1,5,1,0 +4,0,9,0,1,1,0,1,0,0 +4,0,1,0,1,1,0,3,0,0 +2,2,5,5,2,3,1,3,0,1 +4,0,1,0,1,1,0,3,0,0 +2,2,6,6,2,2,1,3,1,0 +2,2,3,0,1,1,1,2,0,0 +2,2,5,0,2,3,1,5,0,1 +3,2,4,0,2,2,0,3,0,0 +2,2,2,0,1,2,0,2,0,0 +1,2,6,6,2,3,0,2,0,1 +1,2,1,0,1,2,0,4,0,0 +3,0,5,0,1,1,1,2,0,0 +4,0,5,0,1,2,0,3,0,0 +4,0,4,0,1,2,0,2,0,0 +2,2,2,0,1,2,0,3,0,1 +4,0,2,0,1,2,1,2,0,0 +2,2,5,0,1,2,0,4,0,0 +0,2,6,0,1,2,1,5,0,0 +2,2,5,0,1,3,1,5,0,1 +2,2,4,0,1,2,1,2,0,1 +1,2,5,0,1,3,0,2,0,0 +1,2,2,0,1,1,1,2,0,1 +3,0,0,0,1,1,1,1,0,0 +3,0,0,0,1,1,0,2,0,0 +4,0,10,0,1,3,1,3,0,1 +3,2,5,0,1,1,0,1,0,0 +4,0,3,3,2,3,0,2,1,1 +2,2,4,0,1,2,0,3,0,0 +2,2,5,4,1,2,1,3,0,1 +3,2,3,4,2,2,0,2,0,0 +3,0,2,0,2,2,0,1,1,0 +3,2,1,0,1,3,0,2,0,0 +1,2,5,6,1,2,1,3,1,1 +4,0,1,0,1,1,0,2,0,0 +2,2,7,0,1,2,1,2,0,0 +3,0,5,6,0,3,0,3,1,0 +2,2,10,0,1,2,1,2,1,1 +3,0,2,0,1,2,1,5,0,0 +3,0,7,4,2,2,0,2,0,0 +1,2,4,4,2,3,0,2,1,1 +4,0,1,0,1,2,0,2,0,0 +4,1,1,0,1,1,0,5,0,0 +1,2,5,0,1,2,0,3,0,1 +1,2,3,4,2,2,0,2,0,1 +3,0,1,0,1,1,1,3,0,0 +4,0,4,0,1,3,1,3,0,0 +3,0,4,4,2,3,1,3,0,0 +2,2,5,5,1,2,0,3,0,0 +4,0,10,0,1,2,0,2,0,0 +3,2,5,0,1,3,0,2,0,0 +2,0,3,4,1,3,1,2,1,1 +3,0,5,5,2,2,0,4,1,1 +4,0,4,4,1,2,1,5,0,1 +2,2,3,0,1,2,0,1,0,0 +2,2,3,0,1,2,0,3,0,0 +2,2,10,0,1,2,0,2,0,0 +3,0,3,0,1,2,1,1,0,1 +3,0,5,4,1,3,1,3,0,1 +2,0,4,0,1,2,0,2,0,0 +3,2,4,0,1,1,1,3,0,1 +2,2,7,4,2,3,1,3,1,0 +2,2,3,0,1,2,1,3,0,0 +2,2,3,4,1,2,1,3,0,0 +2,2,4,6,2,3,1,3,0,1 +2,2,4,0,1,2,1,2,0,1 +2,2,3,0,1,1,1,5,0,0 +1,2,7,0,1,2,1,5,0,0 +4,0,1,5,2,3,0,3,1,1 +2,2,6,0,1,1,0,2,0,0 +3,0,5,4,1,3,0,2,0,1 +2,2,9,0,1,1,0,2,1,0 +4,0,2,0,1,1,0,4,0,0 +2,2,5,0,1,3,1,5,0,0 +2,2,4,0,1,3,0,3,0,1 +3,0,9,0,1,2,1,5,0,0 +3,2,4,0,1,2,1,4,0,0 +3,2,4,0,1,2,0,5,0,1 +2,2,1,0,1,2,0,2,1,0 +4,0,6,5,2,3,0,2,0,1 +4,0,10,0,1,2,1,3,1,0 +2,2,4,0,1,2,1,3,0,0 +1,2,3,4,1,2,1,1,0,0 +1,2,5,0,1,1,1,3,0,1 +4,1,5,0,1,1,0,2,0,0 +2,2,2,1,1,3,1,4,1,0 +4,0,3,0,1,3,1,2,0,1 +1,2,9,0,1,2,0,4,0,0 +2,2,5,0,1,3,0,3,0,0 +4,0,5,0,1,3,0,2,0,0 +2,2,4,0,1,1,1,4,0,0 +2,2,4,0,1,1,0,4,0,0 +4,0,7,4,2,3,1,2,0,1 +3,0,4,0,1,2,0,2,0,0 +3,2,5,0,1,3,1,3,1,1 +2,0,5,4,1,3,0,2,0,1 +2,2,4,0,1,1,1,2,1,0 +2,0,4,1,2,3,0,4,1,1 +2,2,7,0,1,1,0,2,0,1 +2,2,3,0,1,2,0,2,0,0 +3,0,4,0,1,1,0,4,0,0 +2,2,3,0,1,2,1,3,0,0 +5,0,7,0,1,1,1,3,0,0 +4,0,4,0,1,3,0,3,0,1 +3,2,4,0,1,2,0,2,0,0 +4,0,8,0,1,1,1,5,1,1 +3,0,3,0,2,2,1,3,0,0 +3,0,4,0,1,1,0,2,0,0 +3,0,3,0,1,3,0,3,0,0 +2,2,3,4,1,2,1,2,0,0 +3,0,6,0,1,2,0,3,0,0 +1,2,3,0,1,3,0,3,1,1 +4,0,5,0,1,1,1,3,0,0 +4,0,4,0,1,3,1,2,0,0 +2,0,5,0,1,2,0,3,1,0 +1,2,4,0,1,2,0,2,0,0 +2,2,3,0,1,2,0,2,0,1 +1,2,3,0,1,2,0,4,0,0 +2,2,1,0,1,2,1,2,0,0 +3,2,2,0,1,2,1,4,0,0 +3,2,4,0,1,1,1,3,0,0 +4,0,3,0,1,2,1,3,0,0 +4,0,7,0,1,2,1,2,0,1 +1,1,2,0,1,3,1,3,0,0 +2,2,5,1,2,3,0,3,1,1 +4,0,5,0,2,2,1,5,1,1 +3,0,7,5,2,3,0,2,1,1 +3,0,5,0,1,3,0,0,0,1 +5,0,1,0,1,2,0,1,0,0 +1,2,7,0,1,2,0,2,1,0 +2,2,5,0,1,2,1,4,0,0 +2,2,5,0,1,1,0,2,0,0 +4,0,2,0,1,2,0,2,0,0 +2,2,1,0,1,2,0,2,0,0 +4,0,3,0,1,1,0,2,0,0 +3,0,1,0,1,1,0,3,0,0 +3,2,4,0,1,1,0,2,0,0 +3,0,5,6,2,3,0,4,1,1 +3,0,1,0,1,2,0,2,0,0 +2,2,5,0,1,1,0,5,0,0 +5,0,0,0,1,1,0,4,0,0 +2,2,4,0,1,3,1,3,1,0 +3,2,4,0,1,3,1,2,1,1 +3,0,7,0,1,2,0,2,0,0 +4,0,4,0,1,3,0,4,1,1 +2,2,5,4,2,2,1,2,0,0 +3,0,3,0,1,2,0,3,0,1 +5,0,3,0,1,3,0,3,0,0 +1,2,4,0,1,1,0,1,0,0 +4,0,5,0,1,2,0,2,0,0 +2,2,3,4,2,2,1,5,1,1 +3,0,5,6,0,3,0,2,1,0 +3,0,0,0,1,2,0,1,0,0 +2,2,3,0,1,3,1,2,1,0 +1,2,6,0,1,3,0,2,0,1 +4,0,5,0,1,1,0,3,0,0 +4,0,3,0,1,1,0,2,0,0 +3,0,4,5,1,3,0,2,1,1 +3,2,6,2,2,3,1,5,0,1 +1,2,3,4,2,2,1,3,1,0 +2,2,3,5,1,2,1,2,1,0 +3,0,6,0,1,3,0,2,0,0 +3,2,6,0,1,2,1,3,0,0 +2,2,4,0,1,2,0,3,1,0 +2,2,6,0,1,2,1,5,0,0 +3,2,5,4,2,2,0,2,1,0 +2,2,3,0,1,2,1,5,0,0 +4,0,2,0,1,3,1,3,1,0 +3,0,5,5,2,2,0,2,0,0 +3,2,4,4,2,2,0,2,1,0 +1,2,5,5,2,2,1,5,0,0 +3,2,2,0,1,2,1,2,0,0 +3,0,7,0,1,3,0,5,0,0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/breast_cancer.tsv Wed May 28 11:30:50 2025 +0000 @@ -0,0 +1,287 @@ +age menopause tumor-size inv-nodes node-caps deg-malig breast breast-quad irradiat target +2 2 2 0 2 3 1 3 0 1 +3 0 2 0 1 1 1 1 0 0 +3 0 6 0 1 2 0 2 0 1 +2 2 6 0 2 3 1 2 1 0 +2 2 5 4 2 2 0 5 0 1 +3 2 4 4 1 2 1 3 1 0 +3 0 7 0 1 3 0 3 0 0 +2 2 1 0 1 2 0 3 0 0 +2 2 0 0 1 2 1 4 0 0 +2 0 7 2 2 2 1 3 1 0 +3 2 4 0 1 2 0 2 0 0 +4 0 2 0 1 2 1 3 0 0 +3 0 5 0 1 1 1 1 0 0 +3 0 4 0 1 2 1 3 0 0 +2 2 4 0 1 2 0 2 1 1 +1 2 3 0 1 3 0 1 0 0 +3 2 1 4 1 1 1 3 0 0 +4 0 2 0 1 2 1 3 0 0 +3 2 7 0 1 2 0 3 0 0 +3 0 3 0 1 3 0 3 0 0 +3 1 3 0 0 1 0 2 0 1 +4 0 7 4 1 2 1 3 1 0 +3 0 2 0 1 2 1 2 0 0 +2 2 1 0 1 1 1 3 0 0 +1 2 2 5 2 3 0 2 1 1 +3 0 3 4 2 2 1 3 0 0 +3 0 1 0 1 2 1 2 0 0 +2 2 1 0 1 1 1 3 0 0 +4 0 5 4 2 3 0 2 0 0 +2 2 2 2 2 3 0 2 0 1 +4 0 5 0 1 3 1 1 0 1 +4 0 4 4 0 1 1 2 1 0 +3 0 4 0 1 3 0 5 0 0 +3 0 3 0 1 3 1 3 0 0 +2 2 5 0 1 1 0 2 1 1 +1 2 2 0 1 1 0 2 0 0 +2 2 1 0 1 2 1 3 0 0 +4 0 8 5 2 3 0 1 0 0 +2 0 3 0 1 3 0 2 0 0 +2 2 1 0 1 1 1 4 0 0 +1 2 6 0 1 3 0 2 0 1 +2 2 6 6 2 2 1 5 1 0 +4 0 4 0 1 2 1 2 0 0 +3 0 3 4 2 3 1 5 0 1 +1 2 2 0 1 1 0 2 0 0 +3 2 5 0 1 3 0 5 0 1 +4 0 1 0 1 2 1 3 1 0 +2 2 6 0 2 3 1 3 1 0 +3 2 10 0 2 2 1 3 1 0 +3 0 7 0 1 3 1 3 0 0 +5 0 2 6 0 1 0 2 1 1 +3 1 5 0 1 3 1 3 0 0 +2 2 0 0 1 3 0 1 0 0 +5 0 7 0 1 1 1 5 0 0 +2 2 4 0 0 2 0 4 1 0 +3 0 4 2 2 3 1 3 0 0 +3 2 3 0 1 1 0 2 0 0 +3 0 6 2 1 3 0 2 0 0 +3 0 10 0 1 1 1 5 0 0 +1 2 0 0 1 2 1 1 0 1 +3 0 7 5 2 3 0 2 1 1 +2 2 5 0 1 2 1 5 1 0 +2 0 3 0 1 3 0 3 0 0 +2 2 5 2 2 3 0 2 0 1 +2 0 3 0 1 2 1 3 0 1 +3 0 2 0 1 1 1 1 0 0 +1 2 4 0 1 2 1 2 0 0 +4 0 2 0 1 2 0 2 0 0 +3 2 10 6 2 2 1 3 0 1 +1 2 1 0 1 1 1 2 0 0 +3 2 4 4 2 3 0 2 1 1 +4 0 4 4 0 1 1 3 1 0 +4 0 1 0 1 1 1 2 0 0 +3 0 5 5 2 3 0 4 0 1 +1 2 4 5 2 3 0 4 1 1 +3 0 1 0 1 1 0 2 0 0 +3 2 2 0 1 1 0 2 0 0 +2 2 4 0 1 2 1 1 0 0 +2 2 4 0 1 3 0 5 0 1 +4 0 5 5 2 2 1 5 0 0 +3 1 2 0 1 2 0 2 0 0 +2 2 4 0 1 2 1 2 0 0 +2 2 5 0 1 1 1 3 0 0 +4 0 2 0 1 2 0 3 1 0 +1 2 0 0 1 2 1 1 0 0 +3 0 6 0 1 3 0 3 0 0 +2 2 7 0 1 1 1 3 0 0 +1 2 4 5 2 2 1 3 1 0 +3 0 3 0 1 1 1 2 0 0 +3 0 5 0 1 1 0 3 0 0 +4 0 3 0 1 1 1 3 0 1 +1 2 5 4 1 3 1 3 1 1 +3 1 3 0 0 1 0 3 0 1 +3 2 1 0 1 2 1 3 0 0 +3 0 3 0 1 2 1 3 0 0 +2 2 8 0 1 2 0 2 1 0 +1 2 7 0 1 1 0 3 0 1 +3 2 1 0 1 1 0 2 0 0 +4 0 5 0 1 3 1 3 1 1 +2 2 6 0 1 1 1 3 0 1 +2 2 3 4 2 2 0 2 1 1 +3 2 2 0 1 2 0 2 0 1 +3 0 5 0 1 3 1 2 0 0 +4 0 3 0 1 2 0 3 0 0 +2 2 3 0 1 1 0 4 0 0 +4 0 5 4 2 2 0 1 1 1 +4 0 3 4 1 2 0 2 1 1 +3 2 4 0 1 2 0 5 0 1 +3 0 5 0 1 1 1 5 0 0 +2 2 3 0 1 2 0 4 0 0 +4 0 2 0 1 1 1 3 0 0 +4 0 5 0 1 2 0 2 1 0 +1 2 5 0 1 2 0 3 0 0 +1 2 7 4 1 3 1 5 1 0 +4 0 9 0 1 1 0 1 0 0 +4 0 1 0 1 1 0 3 0 0 +2 2 5 5 2 3 1 3 0 1 +4 0 1 0 1 1 0 3 0 0 +2 2 6 6 2 2 1 3 1 0 +2 2 3 0 1 1 1 2 0 0 +2 2 5 0 2 3 1 5 0 1 +3 2 4 0 2 2 0 3 0 0 +2 2 2 0 1 2 0 2 0 0 +1 2 6 6 2 3 0 2 0 1 +1 2 1 0 1 2 0 4 0 0 +3 0 5 0 1 1 1 2 0 0 +4 0 5 0 1 2 0 3 0 0 +4 0 4 0 1 2 0 2 0 0 +2 2 2 0 1 2 0 3 0 1 +4 0 2 0 1 2 1 2 0 0 +2 2 5 0 1 2 0 4 0 0 +0 2 6 0 1 2 1 5 0 0 +2 2 5 0 1 3 1 5 0 1 +2 2 4 0 1 2 1 2 0 1 +1 2 5 0 1 3 0 2 0 0 +1 2 2 0 1 1 1 2 0 1 +3 0 0 0 1 1 1 1 0 0 +3 0 0 0 1 1 0 2 0 0 +4 0 10 0 1 3 1 3 0 1 +3 2 5 0 1 1 0 1 0 0 +4 0 3 3 2 3 0 2 1 1 +2 2 4 0 1 2 0 3 0 0 +2 2 5 4 1 2 1 3 0 1 +3 2 3 4 2 2 0 2 0 0 +3 0 2 0 2 2 0 1 1 0 +3 2 1 0 1 3 0 2 0 0 +1 2 5 6 1 2 1 3 1 1 +4 0 1 0 1 1 0 2 0 0 +2 2 7 0 1 2 1 2 0 0 +3 0 5 6 0 3 0 3 1 0 +2 2 10 0 1 2 1 2 1 1 +3 0 2 0 1 2 1 5 0 0 +3 0 7 4 2 2 0 2 0 0 +1 2 4 4 2 3 0 2 1 1 +4 0 1 0 1 2 0 2 0 0 +4 1 1 0 1 1 0 5 0 0 +1 2 5 0 1 2 0 3 0 1 +1 2 3 4 2 2 0 2 0 1 +3 0 1 0 1 1 1 3 0 0 +4 0 4 0 1 3 1 3 0 0 +3 0 4 4 2 3 1 3 0 0 +2 2 5 5 1 2 0 3 0 0 +4 0 10 0 1 2 0 2 0 0 +3 2 5 0 1 3 0 2 0 0 +2 0 3 4 1 3 1 2 1 1 +3 0 5 5 2 2 0 4 1 1 +4 0 4 4 1 2 1 5 0 1 +2 2 3 0 1 2 0 1 0 0 +2 2 3 0 1 2 0 3 0 0 +2 2 10 0 1 2 0 2 0 0 +3 0 3 0 1 2 1 1 0 1 +3 0 5 4 1 3 1 3 0 1 +2 0 4 0 1 2 0 2 0 0 +3 2 4 0 1 1 1 3 0 1 +2 2 7 4 2 3 1 3 1 0 +2 2 3 0 1 2 1 3 0 0 +2 2 3 4 1 2 1 3 0 0 +2 2 4 6 2 3 1 3 0 1 +2 2 4 0 1 2 1 2 0 1 +2 2 3 0 1 1 1 5 0 0 +1 2 7 0 1 2 1 5 0 0 +4 0 1 5 2 3 0 3 1 1 +2 2 6 0 1 1 0 2 0 0 +3 0 5 4 1 3 0 2 0 1 +2 2 9 0 1 1 0 2 1 0 +4 0 2 0 1 1 0 4 0 0 +2 2 5 0 1 3 1 5 0 0 +2 2 4 0 1 3 0 3 0 1 +3 0 9 0 1 2 1 5 0 0 +3 2 4 0 1 2 1 4 0 0 +3 2 4 0 1 2 0 5 0 1 +2 2 1 0 1 2 0 2 1 0 +4 0 6 5 2 3 0 2 0 1 +4 0 10 0 1 2 1 3 1 0 +2 2 4 0 1 2 1 3 0 0 +1 2 3 4 1 2 1 1 0 0 +1 2 5 0 1 1 1 3 0 1 +4 1 5 0 1 1 0 2 0 0 +2 2 2 1 1 3 1 4 1 0 +4 0 3 0 1 3 1 2 0 1 +1 2 9 0 1 2 0 4 0 0 +2 2 5 0 1 3 0 3 0 0 +4 0 5 0 1 3 0 2 0 0 +2 2 4 0 1 1 1 4 0 0 +2 2 4 0 1 1 0 4 0 0 +4 0 7 4 2 3 1 2 0 1 +3 0 4 0 1 2 0 2 0 0 +3 2 5 0 1 3 1 3 1 1 +2 0 5 4 1 3 0 2 0 1 +2 2 4 0 1 1 1 2 1 0 +2 0 4 1 2 3 0 4 1 1 +2 2 7 0 1 1 0 2 0 1 +2 2 3 0 1 2 0 2 0 0 +3 0 4 0 1 1 0 4 0 0 +2 2 3 0 1 2 1 3 0 0 +5 0 7 0 1 1 1 3 0 0 +4 0 4 0 1 3 0 3 0 1 +3 2 4 0 1 2 0 2 0 0 +4 0 8 0 1 1 1 5 1 1 +3 0 3 0 2 2 1 3 0 0 +3 0 4 0 1 1 0 2 0 0 +3 0 3 0 1 3 0 3 0 0 +2 2 3 4 1 2 1 2 0 0 +3 0 6 0 1 2 0 3 0 0 +1 2 3 0 1 3 0 3 1 1 +4 0 5 0 1 1 1 3 0 0 +4 0 4 0 1 3 1 2 0 0 +2 0 5 0 1 2 0 3 1 0 +1 2 4 0 1 2 0 2 0 0 +2 2 3 0 1 2 0 2 0 1 +1 2 3 0 1 2 0 4 0 0 +2 2 1 0 1 2 1 2 0 0 +3 2 2 0 1 2 1 4 0 0 +3 2 4 0 1 1 1 3 0 0 +4 0 3 0 1 2 1 3 0 0 +4 0 7 0 1 2 1 2 0 1 +1 1 2 0 1 3 1 3 0 0 +2 2 5 1 2 3 0 3 1 1 +4 0 5 0 2 2 1 5 1 1 +3 0 7 5 2 3 0 2 1 1 +3 0 5 0 1 3 0 0 0 1 +5 0 1 0 1 2 0 1 0 0 +1 2 7 0 1 2 0 2 1 0 +2 2 5 0 1 2 1 4 0 0 +2 2 5 0 1 1 0 2 0 0 +4 0 2 0 1 2 0 2 0 0 +2 2 1 0 1 2 0 2 0 0 +4 0 3 0 1 1 0 2 0 0 +3 0 1 0 1 1 0 3 0 0 +3 2 4 0 1 1 0 2 0 0 +3 0 5 6 2 3 0 4 1 1 +3 0 1 0 1 2 0 2 0 0 +2 2 5 0 1 1 0 5 0 0 +5 0 0 0 1 1 0 4 0 0 +2 2 4 0 1 3 1 3 1 0 +3 2 4 0 1 3 1 2 1 1 +3 0 7 0 1 2 0 2 0 0 +4 0 4 0 1 3 0 4 1 1 +2 2 5 4 2 2 1 2 0 0 +3 0 3 0 1 2 0 3 0 1 +5 0 3 0 1 3 0 3 0 0 +1 2 4 0 1 1 0 1 0 0 +4 0 5 0 1 2 0 2 0 0 +2 2 3 4 2 2 1 5 1 1 +3 0 5 6 0 3 0 2 1 0 +3 0 0 0 1 2 0 1 0 0 +2 2 3 0 1 3 1 2 1 0 +1 2 6 0 1 3 0 2 0 1 +4 0 5 0 1 1 0 3 0 0 +4 0 3 0 1 1 0 2 0 0 +3 0 4 5 1 3 0 2 1 1 +3 2 6 2 2 3 1 5 0 1 +1 2 3 4 2 2 1 3 1 0 +2 2 3 5 1 2 1 2 1 0 +3 0 6 0 1 3 0 2 0 0 +3 2 6 0 1 2 1 3 0 0 +2 2 4 0 1 2 0 3 1 0 +2 2 6 0 1 2 1 5 0 0 +3 2 5 4 2 2 0 2 1 0 +2 2 3 0 1 2 1 5 0 0 +4 0 2 0 1 3 1 3 1 0 +3 0 5 5 2 2 0 2 0 0 +3 2 4 4 2 2 0 2 1 0 +1 2 5 5 2 2 1 5 0 0 +3 2 2 0 1 2 1 2 0 0 +3 0 7 0 1 3 0 5 0 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/reg_1027_ESL.csv Wed May 28 11:30:50 2025 +0000 @@ -0,0 +1,489 @@ +in1,in2,in3,in4,target +6.0,5.0,6.0,6.0,6.0 +5.0,4.0,5.0,5.0,5.0 +5.0,3.0,4.0,5.0,4.0 +6.0,5.0,6.0,7.0,6.0 +4.0,3.0,3.0,5.0,3.0 +9.0,6.0,6.0,6.0,6.0 +5.0,5.0,5.0,5.0,4.0 +5.0,3.0,2.0,2.0,2.0 +5.0,5.0,5.0,5.0,5.0 +5.0,4.0,6.0,6.0,6.0 +6.0,5.0,7.0,6.0,6.0 +8.0,5.0,6.0,6.0,6.0 +4.0,3.0,4.0,4.0,3.0 +6.0,6.0,5.0,5.0,5.0 +4.0,4.0,5.0,7.0,5.0 +6.0,3.0,5.0,5.0,4.0 +6.0,6.0,4.0,5.0,5.0 +6.0,5.0,5.0,6.0,6.0 +4.0,4.0,4.0,5.0,4.0 +6.0,6.0,6.0,7.0,7.0 +8.0,7.0,7.0,5.0,6.0 +2.0,1.0,2.0,4.0,2.0 +4.0,5.0,6.0,5.0,5.0 +7.0,6.0,5.0,6.0,6.0 +6.0,5.0,6.0,7.0,7.0 +9.0,8.0,6.0,6.0,7.0 +1.0,2.0,3.0,5.0,2.0 +6.0,6.0,6.0,6.0,5.0 +5.0,5.0,6.0,7.0,6.0 +7.0,6.0,6.0,6.0,6.0 +6.0,5.0,6.0,7.0,6.0 +4.0,3.0,5.0,6.0,4.0 +3.0,3.0,5.0,4.0,3.0 +5.0,4.0,4.0,5.0,5.0 +7.0,8.0,6.0,5.0,6.0 +4.0,4.0,4.0,6.0,4.0 +5.0,5.0,5.0,5.0,5.0 +6.0,7.0,6.0,6.0,6.0 +4.0,3.0,5.0,5.0,4.0 +5.0,4.0,4.0,5.0,4.0 +5.0,5.0,5.0,6.0,5.0 +4.0,4.0,4.0,5.0,4.0 +5.0,6.0,5.0,5.0,5.0 +6.0,6.0,6.0,7.0,7.0 +7.0,6.0,7.0,6.0,7.0 +2.0,1.0,4.0,5.0,2.0 +6.0,4.0,5.0,6.0,5.0 +2.0,2.0,2.0,5.0,3.0 +4.0,4.0,5.0,5.0,4.0 +5.0,5.0,6.0,6.0,5.0 +6.0,5.0,5.0,5.0,4.0 +5.0,7.0,6.0,5.0,5.0 +8.0,7.0,7.0,6.0,7.0 +6.0,6.0,6.0,6.0,6.0 +6.0,6.0,7.0,6.0,6.0 +7.0,6.0,5.0,5.0,5.0 +4.0,4.0,5.0,6.0,5.0 +8.0,9.0,5.0,6.0,7.0 +4.0,6.0,6.0,6.0,6.0 +6.0,5.0,7.0,5.0,6.0 +4.0,3.0,4.0,6.0,3.0 +6.0,6.0,6.0,6.0,6.0 +6.0,4.0,6.0,6.0,4.0 +7.0,6.0,6.0,7.0,6.0 +6.0,5.0,4.0,5.0,5.0 +7.0,8.0,6.0,7.0,8.0 +7.0,7.0,6.0,6.0,6.0 +7.0,7.0,6.0,5.0,6.0 +6.0,6.0,6.0,5.0,6.0 +7.0,5.0,7.0,6.0,6.0 +6.0,7.0,6.0,5.0,5.0 +5.0,4.0,4.0,6.0,4.0 +6.0,6.0,5.0,7.0,6.0 +6.0,7.0,6.0,6.0,6.0 +6.0,5.0,5.0,5.0,5.0 +3.0,4.0,5.0,6.0,4.0 +6.0,6.0,5.0,6.0,6.0 +5.0,4.0,6.0,5.0,5.0 +4.0,3.0,6.0,5.0,4.0 +5.0,5.0,6.0,5.0,5.0 +7.0,6.0,6.0,7.0,7.0 +6.0,5.0,6.0,6.0,6.0 +7.0,6.0,6.0,7.0,7.0 +6.0,7.0,7.0,6.0,6.0 +6.0,7.0,7.0,6.0,7.0 +8.0,8.0,6.0,7.0,8.0 +4.0,5.0,3.0,4.0,3.0 +6.0,7.0,5.0,4.0,5.0 +8.0,8.0,5.0,6.0,7.0 +8.0,7.0,8.0,7.0,7.0 +5.0,5.0,6.0,6.0,6.0 +6.0,6.0,6.0,6.0,6.0 +6.0,4.0,5.0,6.0,6.0 +7.0,6.0,6.0,6.0,7.0 +6.0,6.0,5.0,5.0,5.0 +8.0,7.0,7.0,6.0,7.0 +3.0,3.0,4.0,5.0,4.0 +7.0,5.0,5.0,6.0,6.0 +6.0,6.0,3.0,5.0,4.0 +5.0,8.0,6.0,6.0,6.0 +5.0,3.0,6.0,7.0,6.0 +7.0,6.0,7.0,6.0,7.0 +6.0,5.0,5.0,5.0,5.0 +3.0,2.0,2.0,6.0,1.0 +7.0,6.0,5.0,6.0,5.0 +8.0,6.0,7.0,7.0,8.0 +4.0,3.0,4.0,4.0,4.0 +7.0,7.0,7.0,7.0,9.0 +7.0,7.0,7.0,7.0,7.0 +9.0,8.0,6.0,5.0,7.0 +6.0,4.0,6.0,6.0,5.0 +7.0,7.0,7.0,7.0,8.0 +4.0,5.0,4.0,5.0,4.0 +6.0,6.0,6.0,6.0,6.0 +6.0,6.0,5.0,5.0,5.0 +6.0,5.0,7.0,6.0,6.0 +7.0,6.0,6.0,6.0,6.0 +7.0,7.0,6.0,5.0,6.0 +5.0,5.0,6.0,6.0,6.0 +7.0,6.0,6.0,5.0,6.0 +7.0,7.0,7.0,6.0,7.0 +5.0,4.0,5.0,6.0,4.0 +5.0,4.0,3.0,2.0,1.0 +5.0,5.0,5.0,6.0,5.0 +6.0,5.0,5.0,6.0,5.0 +4.0,3.0,3.0,4.0,3.0 +4.0,3.0,5.0,6.0,4.0 +6.0,5.0,6.0,6.0,6.0 +4.0,2.0,3.0,4.0,3.0 +6.0,5.0,6.0,5.0,6.0 +6.0,5.0,6.0,6.0,6.0 +6.0,7.0,7.0,7.0,7.0 +2.0,3.0,5.0,4.0,3.0 +4.0,6.0,4.0,5.0,4.0 +6.0,6.0,7.0,6.0,6.0 +3.0,3.0,4.0,4.0,3.0 +4.0,6.0,5.0,4.0,4.0 +5.0,3.0,5.0,7.0,5.0 +6.0,4.0,5.0,6.0,5.0 +3.0,3.0,4.0,5.0,4.0 +2.0,2.0,4.0,6.0,4.0 +8.0,8.0,7.0,6.0,7.0 +8.0,8.0,7.0,6.0,8.0 +6.0,6.0,6.0,6.0,6.0 +7.0,7.0,6.0,6.0,6.0 +6.0,6.0,6.0,6.0,6.0 +7.0,5.0,5.0,5.0,5.0 +5.0,5.0,4.0,4.0,4.0 +5.0,5.0,6.0,7.0,6.0 +6.0,6.0,5.0,5.0,5.0 +5.0,6.0,4.0,5.0,4.0 +3.0,3.0,3.0,5.0,3.0 +3.0,3.0,4.0,5.0,4.0 +4.0,3.0,4.0,5.0,4.0 +6.0,5.0,5.0,5.0,4.0 +6.0,5.0,5.0,6.0,6.0 +4.0,4.0,5.0,6.0,5.0 +6.0,5.0,6.0,6.0,6.0 +6.0,6.0,6.0,6.0,7.0 +5.0,4.0,5.0,5.0,4.0 +5.0,6.0,6.0,6.0,6.0 +6.0,6.0,6.0,7.0,8.0 +5.0,5.0,4.0,4.0,4.0 +6.0,6.0,7.0,6.0,6.0 +6.0,7.0,6.0,6.0,6.0 +5.0,3.0,5.0,6.0,5.0 +4.0,4.0,6.0,6.0,5.0 +8.0,8.0,6.0,6.0,8.0 +7.0,9.0,6.0,5.0,6.0 +4.0,5.0,5.0,5.0,4.0 +5.0,4.0,6.0,6.0,6.0 +4.0,3.0,5.0,5.0,4.0 +6.0,4.0,6.0,6.0,6.0 +6.0,5.0,6.0,6.0,6.0 +6.0,5.0,4.0,5.0,4.0 +5.0,3.0,6.0,6.0,5.0 +6.0,5.0,6.0,7.0,6.0 +4.0,5.0,5.0,4.0,4.0 +6.0,5.0,6.0,6.0,6.0 +8.0,8.0,7.0,7.0,8.0 +5.0,6.0,5.0,5.0,5.0 +8.0,7.0,8.0,7.0,8.0 +6.0,6.0,6.0,6.0,6.0 +7.0,5.0,6.0,7.0,7.0 +5.0,4.0,5.0,5.0,4.0 +6.0,5.0,5.0,6.0,5.0 +5.0,5.0,5.0,5.0,5.0 +3.0,1.0,4.0,4.0,3.0 +6.0,7.0,7.0,6.0,7.0 +3.0,4.0,4.0,5.0,4.0 +4.0,4.0,5.0,6.0,5.0 +5.0,3.0,5.0,6.0,4.0 +8.0,8.0,6.0,4.0,4.0 +6.0,5.0,5.0,5.0,5.0 +5.0,4.0,6.0,5.0,5.0 +8.0,5.0,7.0,7.0,7.0 +8.0,7.0,7.0,7.0,8.0 +4.0,2.0,3.0,4.0,2.0 +5.0,5.0,5.0,5.0,5.0 +2.0,2.0,2.0,4.0,2.0 +5.0,3.0,6.0,6.0,5.0 +3.0,3.0,3.0,5.0,3.0 +4.0,4.0,3.0,3.0,3.0 +8.0,6.0,7.0,6.0,8.0 +7.0,6.0,7.0,6.0,7.0 +7.0,5.0,5.0,6.0,6.0 +6.0,4.0,6.0,6.0,6.0 +6.0,4.0,3.0,5.0,4.0 +8.0,5.0,7.0,6.0,8.0 +9.0,6.0,7.0,8.0,9.0 +6.0,7.0,7.0,6.0,6.0 +3.0,3.0,3.0,5.0,3.0 +5.0,5.0,6.0,5.0,5.0 +6.0,7.0,6.0,6.0,6.0 +7.0,6.0,6.0,5.0,6.0 +8.0,7.0,8.0,7.0,9.0 +5.0,6.0,7.0,6.0,6.0 +6.0,5.0,5.0,5.0,5.0 +3.0,4.0,6.0,5.0,4.0 +5.0,3.0,4.0,5.0,4.0 +4.0,5.0,6.0,6.0,5.0 +4.0,3.0,4.0,5.0,4.0 +2.0,3.0,3.0,6.0,4.0 +8.0,8.0,7.0,8.0,9.0 +6.0,6.0,5.0,5.0,5.0 +4.0,3.0,5.0,5.0,4.0 +6.0,6.0,7.0,6.0,6.0 +7.0,8.0,6.0,6.0,8.0 +5.0,4.0,4.0,5.0,4.0 +4.0,3.0,5.0,5.0,3.0 +4.0,3.0,4.0,5.0,4.0 +8.0,7.0,6.0,7.0,7.0 +5.0,4.0,5.0,6.0,5.0 +5.0,5.0,5.0,5.0,5.0 +6.0,6.0,6.0,7.0,6.0 +4.0,3.0,4.0,6.0,4.0 +6.0,5.0,5.0,6.0,5.0 +4.0,4.0,5.0,6.0,5.0 +5.0,5.0,6.0,6.0,6.0 +7.0,7.0,7.0,5.0,6.0 +5.0,4.0,4.0,5.0,5.0 +4.0,3.0,3.0,4.0,3.0 +3.0,3.0,5.0,5.0,4.0 +6.0,7.0,6.0,5.0,6.0 +5.0,4.0,5.0,5.0,5.0 +8.0,5.0,6.0,5.0,6.0 +2.0,3.0,3.0,3.0,2.0 +6.0,5.0,4.0,4.0,3.0 +5.0,5.0,4.0,5.0,5.0 +4.0,3.0,5.0,6.0,4.0 +4.0,4.0,5.0,6.0,5.0 +7.0,7.0,6.0,6.0,6.0 +2.0,2.0,3.0,4.0,2.0 +5.0,4.0,5.0,6.0,4.0 +7.0,8.0,6.0,7.0,7.0 +5.0,4.0,5.0,5.0,4.0 +3.0,3.0,4.0,4.0,4.0 +4.0,4.0,5.0,6.0,5.0 +8.0,7.0,6.0,6.0,6.0 +8.0,4.0,5.0,5.0,4.0 +5.0,6.0,6.0,7.0,7.0 +7.0,5.0,6.0,6.0,6.0 +5.0,4.0,5.0,5.0,5.0 +5.0,4.0,4.0,5.0,4.0 +7.0,6.0,6.0,6.0,6.0 +5.0,4.0,5.0,6.0,5.0 +5.0,5.0,5.0,6.0,5.0 +8.0,7.0,6.0,6.0,6.0 +6.0,5.0,6.0,7.0,7.0 +6.0,7.0,7.0,7.0,7.0 +2.0,2.0,3.0,4.0,2.0 +4.0,2.0,4.0,5.0,3.0 +5.0,5.0,5.0,6.0,5.0 +7.0,6.0,7.0,4.0,5.0 +4.0,3.0,5.0,6.0,4.0 +3.0,5.0,5.0,5.0,4.0 +6.0,3.0,4.0,5.0,3.0 +5.0,5.0,4.0,4.0,3.0 +4.0,4.0,5.0,4.0,3.0 +6.0,6.0,7.0,7.0,7.0 +6.0,6.0,6.0,5.0,5.0 +8.0,8.0,7.0,6.0,7.0 +6.0,5.0,5.0,6.0,5.0 +7.0,6.0,6.0,7.0,7.0 +7.0,6.0,7.0,6.0,7.0 +8.0,6.0,7.0,7.0,8.0 +7.0,6.0,6.0,7.0,8.0 +6.0,6.0,6.0,5.0,5.0 +3.0,4.0,5.0,4.0,4.0 +5.0,6.0,5.0,5.0,5.0 +5.0,6.0,6.0,6.0,6.0 +4.0,2.0,5.0,6.0,4.0 +6.0,6.0,7.0,7.0,6.0 +6.0,5.0,7.0,7.0,6.0 +6.0,7.0,6.0,7.0,7.0 +4.0,4.0,4.0,5.0,4.0 +5.0,4.0,5.0,5.0,4.0 +4.0,4.0,4.0,5.0,4.0 +6.0,5.0,5.0,5.0,5.0 +7.0,4.0,4.0,5.0,3.0 +6.0,6.0,7.0,7.0,7.0 +8.0,5.0,6.0,6.0,7.0 +2.0,1.0,4.0,4.0,2.0 +5.0,6.0,5.0,5.0,5.0 +5.0,6.0,6.0,6.0,6.0 +6.0,5.0,6.0,5.0,5.0 +4.0,4.0,5.0,7.0,5.0 +7.0,6.0,6.0,6.0,6.0 +4.0,6.0,4.0,4.0,4.0 +6.0,7.0,6.0,6.0,6.0 +6.0,5.0,5.0,6.0,6.0 +4.0,5.0,6.0,7.0,5.0 +6.0,5.0,4.0,4.0,4.0 +4.0,4.0,4.0,4.0,4.0 +5.0,5.0,6.0,6.0,6.0 +5.0,6.0,6.0,6.0,6.0 +5.0,6.0,5.0,6.0,6.0 +4.0,5.0,3.0,5.0,3.0 +8.0,7.0,8.0,7.0,8.0 +4.0,6.0,5.0,4.0,4.0 +5.0,4.0,4.0,5.0,4.0 +5.0,6.0,5.0,6.0,5.0 +4.0,3.0,4.0,5.0,3.0 +7.0,7.0,7.0,6.0,6.0 +8.0,6.0,6.0,5.0,5.0 +7.0,5.0,5.0,6.0,6.0 +5.0,4.0,5.0,6.0,5.0 +5.0,5.0,4.0,5.0,4.0 +5.0,6.0,6.0,6.0,6.0 +6.0,6.0,7.0,7.0,7.0 +6.0,7.0,6.0,6.0,6.0 +7.0,6.0,6.0,6.0,6.0 +6.0,5.0,5.0,6.0,5.0 +6.0,6.0,5.0,5.0,5.0 +5.0,4.0,5.0,6.0,5.0 +4.0,5.0,4.0,5.0,3.0 +5.0,5.0,5.0,5.0,5.0 +8.0,6.0,6.0,5.0,6.0 +4.0,4.0,6.0,6.0,5.0 +5.0,5.0,6.0,7.0,6.0 +6.0,7.0,7.0,6.0,6.0 +5.0,5.0,6.0,5.0,5.0 +7.0,7.0,7.0,7.0,7.0 +4.0,6.0,5.0,5.0,5.0 +8.0,6.0,6.0,6.0,6.0 +9.0,7.0,7.0,7.0,8.0 +7.0,6.0,6.0,7.0,7.0 +4.0,5.0,5.0,4.0,4.0 +6.0,6.0,7.0,7.0,7.0 +5.0,4.0,5.0,5.0,5.0 +6.0,6.0,5.0,5.0,5.0 +5.0,5.0,6.0,6.0,6.0 +7.0,7.0,7.0,6.0,5.0 +6.0,3.0,4.0,5.0,3.0 +5.0,5.0,6.0,5.0,5.0 +5.0,6.0,6.0,7.0,6.0 +6.0,5.0,5.0,6.0,6.0 +6.0,8.0,5.0,5.0,7.0 +4.0,3.0,5.0,5.0,4.0 +8.0,6.0,6.0,5.0,6.0 +3.0,4.0,6.0,6.0,5.0 +5.0,4.0,5.0,6.0,5.0 +7.0,5.0,5.0,7.0,6.0 +9.0,8.0,6.0,7.0,7.0 +6.0,6.0,6.0,6.0,6.0 +5.0,6.0,7.0,6.0,6.0 +6.0,5.0,4.0,4.0,4.0 +7.0,5.0,6.0,6.0,6.0 +5.0,6.0,5.0,7.0,6.0 +4.0,3.0,6.0,6.0,5.0 +4.0,4.0,5.0,6.0,4.0 +5.0,5.0,5.0,6.0,5.0 +3.0,3.0,4.0,5.0,4.0 +5.0,7.0,6.0,6.0,6.0 +6.0,6.0,6.0,6.0,6.0 +7.0,6.0,6.0,7.0,7.0 +3.0,4.0,4.0,5.0,4.0 +5.0,4.0,4.0,5.0,4.0 +6.0,6.0,6.0,6.0,6.0 +4.0,4.0,4.0,6.0,4.0 +4.0,2.0,5.0,5.0,3.0 +8.0,7.0,6.0,7.0,7.0 +8.0,7.0,6.0,6.0,6.0 +6.0,6.0,6.0,7.0,7.0 +6.0,5.0,6.0,6.0,6.0 +5.0,6.0,6.0,6.0,6.0 +5.0,5.0,6.0,6.0,6.0 +6.0,7.0,7.0,7.0,7.0 +5.0,2.0,6.0,6.0,5.0 +7.0,6.0,6.0,6.0,6.0 +4.0,4.0,6.0,7.0,6.0 +6.0,6.0,5.0,6.0,5.0 +5.0,4.0,4.0,5.0,4.0 +8.0,7.0,6.0,6.0,7.0 +4.0,3.0,4.0,4.0,3.0 +5.0,6.0,6.0,6.0,6.0 +5.0,3.0,5.0,6.0,4.0 +4.0,3.0,3.0,5.0,3.0 +6.0,7.0,5.0,4.0,4.0 +6.0,6.0,5.0,6.0,6.0 +6.0,4.0,6.0,6.0,5.0 +4.0,3.0,4.0,5.0,4.0 +5.0,6.0,5.0,5.0,5.0 +5.0,4.0,4.0,4.0,4.0 +0.0,0.0,2.0,5.0,4.0 +6.0,6.0,5.0,6.0,6.0 +6.0,7.0,6.0,6.0,6.0 +8.0,8.0,6.0,7.0,7.0 +6.0,5.0,5.0,5.0,5.0 +8.0,8.0,7.0,8.0,8.0 +3.0,4.0,4.0,5.0,4.0 +5.0,4.0,4.0,6.0,4.0 +5.0,6.0,7.0,6.0,6.0 +6.0,6.0,6.0,6.0,6.0 +6.0,4.0,5.0,6.0,5.0 +3.0,2.0,5.0,6.0,4.0 +5.0,5.0,6.0,5.0,5.0 +5.0,4.0,4.0,5.0,4.0 +8.0,8.0,5.0,6.0,6.0 +6.0,7.0,6.0,6.0,6.0 +6.0,5.0,7.0,7.0,7.0 +6.0,6.0,6.0,7.0,7.0 +5.0,5.0,5.0,5.0,5.0 +6.0,6.0,6.0,4.0,4.0 +2.0,2.0,4.0,5.0,3.0 +4.0,3.0,3.0,3.0,3.0 +6.0,6.0,6.0,5.0,5.0 +3.0,3.0,5.0,5.0,4.0 +3.0,4.0,4.0,3.0,2.0 +5.0,4.0,6.0,7.0,6.0 +6.0,8.0,5.0,5.0,5.0 +5.0,5.0,4.0,4.0,4.0 +5.0,6.0,4.0,5.0,5.0 +7.0,6.0,5.0,6.0,6.0 +4.0,4.0,5.0,5.0,3.0 +8.0,6.0,6.0,7.0,7.0 +5.0,5.0,6.0,6.0,5.0 +6.0,5.0,6.0,5.0,6.0 +8.0,6.0,6.0,6.0,7.0 +5.0,5.0,5.0,6.0,5.0 +4.0,4.0,4.0,5.0,4.0 +5.0,6.0,6.0,5.0,5.0 +5.0,4.0,5.0,6.0,4.0 +6.0,6.0,6.0,7.0,7.0 +6.0,4.0,6.0,5.0,6.0 +6.0,5.0,5.0,6.0,5.0 +4.0,2.0,4.0,6.0,4.0 +4.0,4.0,5.0,5.0,3.0 +5.0,6.0,6.0,5.0,5.0 +6.0,7.0,6.0,5.0,5.0 +5.0,5.0,5.0,3.0,4.0 +4.0,4.0,3.0,3.0,3.0 +6.0,5.0,5.0,6.0,5.0 +9.0,7.0,6.0,6.0,6.0 +5.0,5.0,5.0,6.0,5.0 +6.0,8.0,7.0,6.0,6.0 +6.0,5.0,6.0,6.0,6.0 +6.0,5.0,5.0,7.0,7.0 +4.0,4.0,6.0,5.0,5.0 +3.0,4.0,5.0,6.0,5.0 +6.0,6.0,6.0,6.0,7.0 +3.0,3.0,4.0,5.0,3.0 +8.0,8.0,6.0,6.0,7.0 +6.0,5.0,5.0,5.0,5.0 +7.0,7.0,6.0,4.0,4.0 +8.0,7.0,7.0,6.0,7.0 +8.0,6.0,6.0,6.0,6.0 +6.0,6.0,4.0,4.0,4.0 +8.0,8.0,7.0,6.0,8.0 +5.0,5.0,6.0,6.0,5.0 +6.0,7.0,6.0,6.0,6.0 +6.0,4.0,5.0,5.0,4.0 +4.0,4.0,4.0,5.0,4.0 +5.0,4.0,5.0,5.0,4.0 +4.0,3.0,3.0,5.0,4.0 +4.0,3.0,4.0,5.0,3.0 +2.0,1.0,3.0,4.0,2.0 +5.0,5.0,6.0,6.0,6.0 +7.0,6.0,5.0,5.0,5.0 +7.0,6.0,7.0,7.0,7.0 +4.0,4.0,6.0,6.0,5.0 +7.0,5.0,7.0,7.0,7.0 +8.0,7.0,7.0,6.0,7.0 +4.0,3.0,3.0,5.0,3.0 +6.0,5.0,5.0,6.0,6.0 +4.0,4.0,6.0,8.0,6.0 +8.0,6.0,6.0,7.0,7.0 +7.0,6.0,5.0,5.0,5.0
