Spaces:
Sleeping
Sleeping
ReverseCoder1 commited on
Commit Β·
0c8b295
1
Parent(s): 443a6c2
Readme change final
Browse files
README.md
CHANGED
|
@@ -12,147 +12,487 @@ tags:
|
|
| 12 |
- reinforcement-learning
|
| 13 |
- agent
|
| 14 |
- real-world
|
|
|
|
|
|
|
| 15 |
---
|
| 16 |
|
| 17 |
-
# Data Cleaning OpenEnv
|
| 18 |
|
| 19 |
-
An OpenEnv-
|
| 20 |
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
-
|
| 24 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
|
| 27 |
|
| 28 |
-
|
| 29 |
|
| 30 |
-
|
| 31 |
|
| 32 |
-
|
| 33 |
-
2. Choose a cleaning operation.
|
| 34 |
-
3. Receive dense reward feedback after each action.
|
| 35 |
-
4. Learn not only what to clean, but also the best sequence of operations.
|
| 36 |
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
-
-
|
| 40 |
-
- Provides measurable reward components for quality tracking.
|
| 41 |
-
- Includes sequence penalties, which encourage disciplined cleaning pipelines.
|
| 42 |
-
- Supports benchmarking across multiple task difficulties.
|
| 43 |
|
| 44 |
-
##
|
| 45 |
|
| 46 |
-
| Task ID | Difficulty |
|
| 47 |
-
|---|---|---|---|
|
| 48 |
-
| easy_dedup_rename | Easy | Remove
|
| 49 |
-
| medium_missing_dtype | Medium | Fill missing values
|
| 50 |
-
| hard_full_pipeline | Hard |
|
| 51 |
-
| expert_sales_pipeline | Expert |
|
| 52 |
|
| 53 |
-
|
| 54 |
|
| 55 |
-
|
| 56 |
-
- `fill_missing_mean`
|
| 57 |
-
- `fill_missing_mode`
|
| 58 |
-
- `fill_missing_median`
|
| 59 |
-
- `fix_dtype`
|
| 60 |
-
- `remove_outliers`
|
| 61 |
-
- `rename_columns`
|
| 62 |
-
- `validate_schema`
|
| 63 |
-
- `finish`
|
| 64 |
|
| 65 |
-
|
| 66 |
|
| 67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
-
|
| 70 |
-
-
|
| 71 |
-
-
|
| 72 |
-
- outlier handling quality
|
| 73 |
-
- schema correctness
|
| 74 |
|
| 75 |
-
|
| 76 |
|
| 77 |
-
-
|
| 78 |
-
- repeating unnecessary actions
|
| 79 |
-
- taking too many steps
|
| 80 |
|
| 81 |
-
|
| 82 |
|
| 83 |
-
|
| 84 |
|
| 85 |
-
|
| 86 |
-
- `
|
| 87 |
-
- `
|
| 88 |
-
- `
|
| 89 |
-
- `GET /validate`
|
| 90 |
-
- `GET /health`
|
| 91 |
-
- `GET /ui`
|
| 92 |
|
| 93 |
-
|
|
|
|
|
|
|
| 94 |
|
| 95 |
-
|
| 96 |
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
```
|
| 101 |
|
| 102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
|
| 104 |
```python
|
| 105 |
import requests
|
| 106 |
|
| 107 |
-
|
| 108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
|
| 110 |
-
#
|
| 111 |
-
|
| 112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
|
| 114 |
-
|
| 115 |
```
|
| 116 |
|
| 117 |
-
### Run
|
| 118 |
|
| 119 |
```bash
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
|
|
|
|
|
|
| 123 |
python inference.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
```
|
| 153 |
|
| 154 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
|
| 156 |
-
|
| 157 |
-
- UI (required): https://thorodin103-data-cleaning.hf.space/ui
|
| 158 |
-
- OpenEnv specification: https://github.com/openenv/openenv
|
|
|
|
| 12 |
- reinforcement-learning
|
| 13 |
- agent
|
| 14 |
- real-world
|
| 15 |
+
- tabular
|
| 16 |
+
- pandas
|
| 17 |
---
|
| 18 |
|
| 19 |
+
# π§Ή Data Cleaning OpenEnv
|
| 20 |
|
| 21 |
+
> *An OpenEnv-compliant environment where AI agents learn to clean messy real-world datasets β step by step, with dense reward signals and sequence-aware penalties.*
|
| 22 |
|
| 23 |
+
[](https://thorodin103-data-cleaning.hf.space/ui)
|
| 24 |
+
[](https://huggingface.co/spaces/thorodin103/Data-cleaning/tree/main)
|
| 25 |
+
[](#-openenv-spec-compliance)
|
| 26 |
+
[](LICENSE)
|
| 27 |
+
[](Dockerfile)
|
| 28 |
|
| 29 |
+
| | |
|
| 30 |
+
|---|---|
|
| 31 |
+
| **Live UI** | https://thorodin103-data-cleaning.hf.space/ui |
|
| 32 |
+
| **HF Repository** | https://huggingface.co/spaces/thorodin103/Data-cleaning/tree/main |
|
| 33 |
+
| **API Base** | https://thorodin103-data-cleaning.hf.space |
|
| 34 |
+
| **Validate** | https://thorodin103-data-cleaning.hf.space/validate |
|
| 35 |
+
| **API Docs** | https://thorodin103-data-cleaning.hf.space/docs |
|
| 36 |
|
| 37 |
+
---
|
| 38 |
|
| 39 |
+
## π Why This Environment Exists
|
| 40 |
|
| 41 |
+
Data engineers and analysts spend **up to 80% of their time cleaning data** before it can be used. Despite being one of the most universal tasks in the real world, no existing OpenEnv benchmark captures it.
|
| 42 |
|
| 43 |
+
This environment fills that gap. An AI agent receives a dirty dataset and must apply a sequence of cleaning operations to match a gold-standard output. What makes it non-trivial:
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
+
- **Order matters.** Filling missing values before fixing data types produces wrong results β the reward function knows this and penalizes it.
|
| 46 |
+
- **Partial progress is rewarded.** Every action shifts the score, giving RL agents a dense learning signal rather than sparse end-of-episode feedback.
|
| 47 |
+
- **Four difficulty tiers.** From a 3-step deduplication task to a full expert-level sales pipeline requiring case normalization, outlier removal, and schema validation β in the right sequence.
|
| 48 |
+
- **Fully live.** The environment runs on Hugging Face Spaces, passes `openenv validate`, and exposes a REST API any agent can call against right now.
|
| 49 |
|
| 50 |
+
---
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
+
## π― Tasks
|
| 53 |
|
| 54 |
+
| Task ID | Difficulty | Max Steps | Dataset | What the Agent Must Do |
|
| 55 |
+
|---|---|---|---|---|
|
| 56 |
+
| `easy_dedup_rename` | π’ Easy | 10 | Employee records | Remove duplicate rows + rename columns to snake_case |
|
| 57 |
+
| `medium_missing_dtype` | π‘ Medium | 15 | Customer records | Fill missing values (mean/mode) + fix wrong data types |
|
| 58 |
+
| `hard_full_pipeline` | π΄ Hard | 20 | Orders data | Full pipeline: dedup β fill β fix types β remove outliers β validate schema |
|
| 59 |
+
| `expert_sales_pipeline` | β« Expert | 25 | Sales transactions | Expert pipeline with case standardization + all of the above, in strict order |
|
| 60 |
|
| 61 |
+
---
|
| 62 |
|
| 63 |
+
### Task 1 β Easy: Deduplicate & Rename (`easy_dedup_rename`)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
+
The agent receives an employee dataset with duplicate rows and column names like `EMP ID`, `DEP T`, `SAL ARY`. It must remove the duplicates and rename all columns to `snake_case`.
|
| 66 |
|
| 67 |
+
**Dirty dataset sample:**
|
| 68 |
+
```
|
| 69 |
+
EMP ID | EMP NAME | DEP T | SAL ARY | AGE
|
| 70 |
+
101 | Alice | HR | 50000 | 28
|
| 71 |
+
102 | Bob | IT | 60000 | 35
|
| 72 |
+
102 | Bob | IT | 60000 | 35 β duplicate
|
| 73 |
+
103 | Charlie | IT | 55000 | 29
|
| 74 |
+
103 | Charlie | IT | 55000 | 29 β duplicate
|
| 75 |
+
```
|
| 76 |
|
| 77 |
+
**Scoring:**
|
| 78 |
+
- `duplicate_score` (0.5) β how close row count is to gold
|
| 79 |
+
- `schema_score` (0.5) β proportion of column names matching gold
|
|
|
|
|
|
|
| 80 |
|
| 81 |
+
**Optimal actions:** `remove_duplicates` β `rename_columns` β `finish` (3 steps, score = 0.99)
|
| 82 |
|
| 83 |
+
---
|
|
|
|
|
|
|
| 84 |
|
| 85 |
+
### Task 2 β Medium: Missing Values & Types (`medium_missing_dtype`)
|
| 86 |
|
| 87 |
+
The agent receives a customer dataset where numeric columns like `age`, `purchases`, and `salary` contain missing values and are stored as the wrong type (strings instead of numbers).
|
| 88 |
|
| 89 |
+
**Issues present:**
|
| 90 |
+
- `age` column: 2 missing values, stored as `object` dtype
|
| 91 |
+
- `purchases` column: 3 missing values
|
| 92 |
+
- `salary` column: stored as string, needs numeric conversion
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
+
**Scoring:**
|
| 95 |
+
- `missing_score` (0.5) β proportion of missing values correctly filled
|
| 96 |
+
- `dtype_score` (0.5) β proportion of columns with correct data types
|
| 97 |
|
| 98 |
+
**Key challenge:** The agent must fix types *before* filling missing values with mean/median β doing it backwards triggers a sequence penalty.
|
| 99 |
|
| 100 |
+
---
|
| 101 |
+
|
| 102 |
+
### Task 3 β Hard: Full Pipeline (`hard_full_pipeline`)
|
| 103 |
+
|
| 104 |
+
The agent receives an orders dataset with all classes of data quality issues simultaneously. Must execute the full cleaning pipeline in the correct sequence.
|
| 105 |
+
|
| 106 |
+
**Issues present:**
|
| 107 |
+
- Duplicate order IDs
|
| 108 |
+
- Missing values in `quantity`, `product`, and `rating` columns
|
| 109 |
+
- `quantity` and `price` stored as wrong types
|
| 110 |
+
- Extreme outliers (e.g., `quantity=999`, `price=99999`)
|
| 111 |
+
- Column names not matching gold schema
|
| 112 |
+
|
| 113 |
+
**Scoring:** All 5 components weighted equally at 0.2 each:
|
| 114 |
+
`duplicate_score + missing_score + dtype_score + outlier_score + schema_score`
|
| 115 |
+
|
| 116 |
+
**Why it's hard:** The agent must not only apply all 5 operations but apply them in the correct order. Doing `fill_missing` before `remove_duplicates` incurs a -0.08 penalty. Doing `remove_outliers` before `fix_dtype` incurs another. Penalties compound.
|
| 117 |
+
|
| 118 |
+
---
|
| 119 |
+
|
| 120 |
+
### Task 4 β Expert: Sales Pipeline (`expert_sales_pipeline`)
|
| 121 |
+
|
| 122 |
+
The hardest task. A sales transaction dataset with messy region names (`north`, `EAST`, `South` β all meaning the same thing), missing sales reps and commission values, mixed column naming conventions, and outlier transactions.
|
| 123 |
+
|
| 124 |
+
**Issues present:**
|
| 125 |
+
- Duplicate transactions
|
| 126 |
+
- Mixed-case region names requiring standardization
|
| 127 |
+
- Missing `SALES REP` and `COMMISSION %` values
|
| 128 |
+
- Inconsistent column naming (`Transaction_ID`, `SALES REP`, `Sale Amount` β all need snake_case)
|
| 129 |
+
- Outlier transactions in `Sale Amount` and `Units Sold`
|
| 130 |
+
|
| 131 |
+
**Scoring:**
|
| 132 |
+
- `duplicate_score` (0.15), `missing_score` (0.20), `dtype_score` (0.20), `outlier_score` (0.20), `schema_score` (0.25)
|
| 133 |
+
|
| 134 |
+
**Total max steps: 25** β the most complex episode in the environment.
|
| 135 |
+
|
| 136 |
+
---
|
| 137 |
+
|
| 138 |
+
## ποΈ Observation Space
|
| 139 |
+
|
| 140 |
+
At every step, the agent receives a structured observation describing the current state of the dataset:
|
| 141 |
+
|
| 142 |
+
```json
|
| 143 |
+
{
|
| 144 |
+
"task_id": "easy_dedup_rename",
|
| 145 |
+
"step": 1,
|
| 146 |
+
"dataset_info": {
|
| 147 |
+
"total_rows": 8,
|
| 148 |
+
"total_columns": 5,
|
| 149 |
+
"has_duplicates": true,
|
| 150 |
+
"has_missing": false
|
| 151 |
+
},
|
| 152 |
+
"columns": ["EMP ID", "EMP NAME", "DEP T", "SAL ARY", "AGE"],
|
| 153 |
+
"shape": [8, 5],
|
| 154 |
+
"missing_values": {"EMP ID": 0, "EMP NAME": 0, "DEP T": 0, "SAL ARY": 0, "AGE": 0},
|
| 155 |
+
"dtypes": {"EMP ID": "int64", "EMP NAME": "object", "DEP T": "object", "SAL ARY": "int64", "AGE": "int64"},
|
| 156 |
+
"duplicate_count": 2,
|
| 157 |
+
"sample_rows": [
|
| 158 |
+
{"EMP ID": 101, "EMP NAME": "Alice", "DEP T": "HR", "SAL ARY": 50000, "AGE": 28},
|
| 159 |
+
{"EMP ID": 102, "EMP NAME": "Bob", "DEP T": "IT", "SAL ARY": 60000, "AGE": 35},
|
| 160 |
+
{"EMP ID": 102, "EMP NAME": "Bob", "DEP T": "IT", "SAL ARY": 60000, "AGE": 35}
|
| 161 |
+
],
|
| 162 |
+
"available_operations": ["remove_duplicates", "rename_columns", "finish"],
|
| 163 |
+
"task_description": "Remove duplicate rows and rename columns to snake_case in an employee dataset.",
|
| 164 |
+
"message": "Environment reset. Start cleaning!"
|
| 165 |
+
}
|
| 166 |
```
|
| 167 |
|
| 168 |
+
**What's hidden from the agent:** the gold-standard dataset. The agent only sees the dirty data and its own progress metrics.
|
| 169 |
+
|
| 170 |
+
---
|
| 171 |
+
|
| 172 |
+
## β‘ Action Space
|
| 173 |
+
|
| 174 |
+
Actions are JSON objects with an `operation` and optional `parameters`:
|
| 175 |
+
|
| 176 |
+
```json
|
| 177 |
+
{
|
| 178 |
+
"operation": "fill_missing",
|
| 179 |
+
"parameters": {
|
| 180 |
+
"column": "age",
|
| 181 |
+
"strategy": "mean"
|
| 182 |
+
}
|
| 183 |
+
}
|
| 184 |
+
```
|
| 185 |
+
|
| 186 |
+
| Operation | Parameters | Description |
|
| 187 |
+
|---|---|---|
|
| 188 |
+
| `remove_duplicates` | `subset` (optional list of columns) | Drop duplicate rows |
|
| 189 |
+
| `fill_missing` | `column` (optional), `strategy`: `mean`/`median`/`mode`/`ffill` | Fill NaN values |
|
| 190 |
+
| `fix_dtype` | `column` (optional), `dtype`: `int`/`float`/`str`/`auto` | Cast column types |
|
| 191 |
+
| `remove_outliers` | `column` (optional), `method`: `iqr`/`zscore` | Remove statistical outliers |
|
| 192 |
+
| `rename_columns` | `mapping` (optional dict, auto snake_case if omitted) | Rename column headers |
|
| 193 |
+
| `validate_schema` | β | Check columns against gold standard, returns feedback |
|
| 194 |
+
| `finish` | β | End the episode and lock in the final score |
|
| 195 |
+
|
| 196 |
+
---
|
| 197 |
+
|
| 198 |
+
## π Reward Function
|
| 199 |
+
|
| 200 |
+
Rewards are computed **after every action** β dense signal at every step, not just at episode end.
|
| 201 |
+
|
| 202 |
+
### Components
|
| 203 |
+
|
| 204 |
+
| Component | Formula | Weight (hard task) |
|
| 205 |
+
|---|---|---|
|
| 206 |
+
| `duplicate_score` | `min(1, gold_rows / curr_rows)` | 0.20 |
|
| 207 |
+
| `missing_score` | `filled_so_far / total_needed` | 0.20 |
|
| 208 |
+
| `dtype_score` | `matching_dtypes / total_columns` | 0.20 |
|
| 209 |
+
| `outlier_score` | `1 β outlier_rows / total_rows` | 0.20 |
|
| 210 |
+
| `schema_score` | `matching_cols / gold_cols` | 0.20 |
|
| 211 |
+
| `penalty` | sequence + step violations (subtracted) | β |
|
| 212 |
+
|
| 213 |
+
**Total reward = weighted component sum β penalties, clamped to [0.0, 1.0]**
|
| 214 |
+
|
| 215 |
+
### The Sequence-Penalty Mechanic
|
| 216 |
+
|
| 217 |
+
This is the environment's core design innovation. The optimal cleaning sequence is:
|
| 218 |
+
|
| 219 |
+
```
|
| 220 |
+
1. remove_duplicates β clean redundant data first
|
| 221 |
+
2. fix_dtype β establish correct column types
|
| 222 |
+
3. fill_missing β impute based on correct types
|
| 223 |
+
4. remove_outliers β after type-correct distributions
|
| 224 |
+
5. validate_schema β final check
|
| 225 |
+
```
|
| 226 |
+
|
| 227 |
+
Violations are penalized:
|
| 228 |
+
|
| 229 |
+
| Violation | Penalty |
|
| 230 |
+
|---|---|
|
| 231 |
+
| Out-of-order operation (e.g., `fill_missing` before `fix_dtype`) | β0.08 |
|
| 232 |
+
| Repeated identical operation back-to-back | β0.02 |
|
| 233 |
+
| Exceeding 80% of the step budget | β0.05 |
|
| 234 |
+
| Total penalty cap | 0.25 |
|
| 235 |
+
|
| 236 |
+
**Why this matters for agent training:** An agent that randomly applies operations will peak early then watch its score decay as penalties accumulate. This forces the agent to learn the *why* behind the sequence, not just the *what*.
|
| 237 |
+
|
| 238 |
+
From the baseline run on the hard task β the agent peaks at **0.885** on step 5 then degrades to **0.664** by step 20 by looping between `remove_outliers` and `fix_dtype` in a penalty-accumulating cycle. This is a real learning signal.
|
| 239 |
+
|
| 240 |
+
---
|
| 241 |
+
|
| 242 |
+
## π Baseline Scores
|
| 243 |
+
|
| 244 |
+
Baseline agent: **GPT-4o-mini** via OpenAI API, temperature 0.1.
|
| 245 |
+
|
| 246 |
+
| Task | Difficulty | Final Score | Steps Used | Notes |
|
| 247 |
+
|---|---|---|---|---|
|
| 248 |
+
| `easy_dedup_rename` | π’ Easy | **0.99** | 3 / 10 | Near-perfect β follows optimal sequence |
|
| 249 |
+
| `medium_missing_dtype` | π‘ Medium | **0.70** | 15 / 15 | Hits step limit, oscillates on dtype/fill |
|
| 250 |
+
| `hard_full_pipeline` | π΄ Hard | **0.6636** | 20 / 20 | Peaks at 0.885 then degrades from looping |
|
| 251 |
+
| `expert_sales_pipeline` | β« Expert | **~0.55** | ~20 / 25 | Case normalization is the main challenge |
|
| 252 |
+
| **Average** | β | **~0.75** | β | Significant room for better agents |
|
| 253 |
+
|
| 254 |
+
The gap between easy (0.99) and hard (0.66) demonstrates genuine difficulty scaling. The hard task's reward degradation curve is directly caused by sequence violations β a smarter agent that plans its sequence upfront would score 0.88+.
|
| 255 |
+
|
| 256 |
+
---
|
| 257 |
+
|
| 258 |
+
## π API Reference
|
| 259 |
+
|
| 260 |
+
The environment runs as a live REST API. All endpoints are accessible now:
|
| 261 |
+
|
| 262 |
+
```
|
| 263 |
+
Base URL: https://thorodin103-data-cleaning.hf.space
|
| 264 |
+
```
|
| 265 |
+
|
| 266 |
+
| Method | Endpoint | Description |
|
| 267 |
+
|---|---|---|
|
| 268 |
+
| `GET` | `/health` | Health check β returns `{"status": "ok"}` |
|
| 269 |
+
| `GET` | `/tasks` | List all 4 tasks with metadata |
|
| 270 |
+
| `POST` | `/reset/{task_id}` | Reset environment, returns initial observation |
|
| 271 |
+
| `POST` | `/step/{task_id}` | Submit action, returns observation + reward + done |
|
| 272 |
+
| `GET` | `/state/{task_id}` | Current internal state (for debugging) |
|
| 273 |
+
| `GET` | `/validate` | OpenEnv compliance check β all 4 tasks pass |
|
| 274 |
+
| `GET` | `/leaderboard` | View agent rankings |
|
| 275 |
+
| `GET` | `/docs` | Interactive Swagger UI |
|
| 276 |
+
| `GET` | `/ui` | Live browser demo |
|
| 277 |
+
|
| 278 |
+
**Live validate response (confirmed passing):**
|
| 279 |
+
```json
|
| 280 |
+
{
|
| 281 |
+
"openenv_valid": true,
|
| 282 |
+
"tasks": {
|
| 283 |
+
"easy_dedup_rename": {"status": "passed", "reset": "ok", "step": "ok", "state": "ok"},
|
| 284 |
+
"medium_missing_dtype": {"status": "passed", "reset": "ok", "step": "ok", "state": "ok"},
|
| 285 |
+
"hard_full_pipeline": {"status": "passed", "reset": "ok", "step": "ok", "state": "ok"},
|
| 286 |
+
"expert_sales_pipeline": {"status": "passed", "reset": "ok", "step": "ok", "state": "ok"}
|
| 287 |
+
}
|
| 288 |
+
}
|
| 289 |
+
```
|
| 290 |
+
|
| 291 |
+
---
|
| 292 |
+
|
| 293 |
+
## π Setup & Usage
|
| 294 |
+
|
| 295 |
+
### Option 1 β Use the live API (no setup needed)
|
| 296 |
|
| 297 |
```python
|
| 298 |
import requests
|
| 299 |
|
| 300 |
+
BASE = "https://thorodin103-data-cleaning.hf.space"
|
| 301 |
+
|
| 302 |
+
# Reset the hard task
|
| 303 |
+
obs = requests.post(f"{BASE}/reset/hard_full_pipeline").json()
|
| 304 |
+
print(obs["observation"]["duplicate_count"]) # β 3
|
| 305 |
+
|
| 306 |
+
# Take an action
|
| 307 |
+
result = requests.post(f"{BASE}/step/hard_full_pipeline", json={
|
| 308 |
+
"operation": "remove_duplicates",
|
| 309 |
+
"parameters": {}
|
| 310 |
+
}).json()
|
| 311 |
+
|
| 312 |
+
print(result["reward"]["total"]) # β 0.6955
|
| 313 |
+
print(result["reward"]["duplicate_score"]) # β 1.0
|
| 314 |
+
print(result["done"]) # β False
|
| 315 |
+
|
| 316 |
+
# Get state
|
| 317 |
+
state = requests.get(f"{BASE}/state/hard_full_pipeline").json()
|
| 318 |
+
```
|
| 319 |
+
|
| 320 |
+
### Option 2 β Run locally with Docker
|
| 321 |
+
|
| 322 |
+
```bash
|
| 323 |
+
git clone https://huggingface.co/spaces/thorodin103/Data-cleaning
|
| 324 |
+
cd Data-cleaning
|
| 325 |
+
|
| 326 |
+
docker build -t data-cleaning-openenv .
|
| 327 |
+
docker run -p 7860:7860 data-cleaning-openenv
|
| 328 |
|
| 329 |
+
# Environment now live at http://localhost:7860
|
| 330 |
+
# UI at http://localhost:7860/ui
|
| 331 |
+
```
|
| 332 |
+
|
| 333 |
+
### Option 3 β Run locally without Docker
|
| 334 |
+
|
| 335 |
+
```bash
|
| 336 |
+
pip install fastapi uvicorn pydantic pandas numpy openai python-dotenv
|
| 337 |
|
| 338 |
+
uvicorn main:app --host 0.0.0.0 --port 7860 --reload
|
| 339 |
```
|
| 340 |
|
| 341 |
+
### Option 4 β Run the baseline inference script
|
| 342 |
|
| 343 |
```bash
|
| 344 |
+
export OPENAI_API_KEY=your_key_here
|
| 345 |
+
export MODEL_NAME=gpt-4o-mini
|
| 346 |
+
export API_BASE_URL=https://api.openai.com/v1
|
| 347 |
+
export HF_TOKEN=your_hf_token
|
| 348 |
+
|
| 349 |
python inference.py
|
| 350 |
+
# Runs all 3 core tasks, prints [START] / [STEP] / [END] trace
|
| 351 |
+
# Saves results to baseline_results.json
|
| 352 |
+
```
|
| 353 |
+
|
| 354 |
+
---
|
| 355 |
+
|
| 356 |
+
## π» Programmatic Usage (Python)
|
| 357 |
+
|
| 358 |
+
```python
|
| 359 |
+
from environment import DataCleaningEnv
|
| 360 |
+
from models import Action
|
| 361 |
+
|
| 362 |
+
# Initialize any task
|
| 363 |
+
env = DataCleaningEnv(task_id="hard_full_pipeline")
|
| 364 |
+
|
| 365 |
+
# Reset β returns StepResult with initial observation
|
| 366 |
+
result = env.reset()
|
| 367 |
+
obs = result.observation
|
| 368 |
+
print(f"Dirty dataset: {obs.shape} with {obs.duplicate_count} duplicates")
|
| 369 |
+
# β Dirty dataset: [20, 8] with 3 duplicates
|
| 370 |
+
|
| 371 |
+
# Optimal sequence for the hard task
|
| 372 |
+
actions = [
|
| 373 |
+
Action(operation="remove_duplicates", parameters={}),
|
| 374 |
+
Action(operation="fix_dtype", parameters={"dtype": "auto"}),
|
| 375 |
+
Action(operation="fill_missing", parameters={"strategy": "mean"}),
|
| 376 |
+
Action(operation="remove_outliers", parameters={"method": "iqr"}),
|
| 377 |
+
Action(operation="validate_schema", parameters={}),
|
| 378 |
+
Action(operation="finish", parameters={}),
|
| 379 |
+
]
|
| 380 |
+
|
| 381 |
+
for action in actions:
|
| 382 |
+
result = env.step(action)
|
| 383 |
+
print(f"{action.operation:20s} β reward: {result.reward.total:.4f}")
|
| 384 |
+
|
| 385 |
+
# β remove_duplicates β reward: 0.6955
|
| 386 |
+
# β fix_dtype β reward: 0.8235
|
| 387 |
+
# β fill_missing β reward: 0.8852 (no penalty β correct order)
|
| 388 |
+
# β remove_outliers β reward: 0.9800
|
| 389 |
+
# β validate_schema β reward: 0.9800
|
| 390 |
+
# β finish β reward: 0.9800
|
| 391 |
+
|
| 392 |
+
# Full state inspection
|
| 393 |
+
state = env.state()
|
| 394 |
+
print(state["reward_history"])
|
| 395 |
+
# β [0.6955, 0.8235, 0.8852, 0.9800, 0.9800, 0.9800]
|
| 396 |
```
|
| 397 |
|
| 398 |
+
---
|
| 399 |
+
|
| 400 |
+
## π§ͺ OpenEnv Spec Compliance
|
| 401 |
+
|
| 402 |
+
All four required interface methods are implemented:
|
| 403 |
|
| 404 |
+
| Method | Signature | Returns |
|
| 405 |
+
|---|---|---|
|
| 406 |
+
| `reset()` | `env.reset()` | `StepResult` (obs + reward + done + info) |
|
| 407 |
+
| `step(action)` | `env.step(Action)` | `StepResult` |
|
| 408 |
+
| `state()` | `env.state()` | `Dict` with full internal state |
|
| 409 |
+
| *(validation)* | `GET /validate` | `{"openenv_valid": true, ...}` |
|
| 410 |
|
| 411 |
+
All models are strict Pydantic v2:
|
| 412 |
|
| 413 |
+
```python
|
| 414 |
+
class Action(BaseModel):
|
| 415 |
+
operation: str
|
| 416 |
+
parameters: Dict[str, Any] = {}
|
| 417 |
+
|
| 418 |
+
class Observation(BaseModel):
|
| 419 |
+
task_id, step, dataset_info, columns, shape,
|
| 420 |
+
missing_values, dtypes, duplicate_count,
|
| 421 |
+
sample_rows, available_operations,
|
| 422 |
+
task_description, message
|
| 423 |
+
|
| 424 |
+
class Reward(BaseModel):
|
| 425 |
+
total, duplicate_score, missing_score,
|
| 426 |
+
dtype_score, outlier_score, schema_score, penalty
|
| 427 |
+
|
| 428 |
+
class StepResult(BaseModel):
|
| 429 |
+
observation: Observation
|
| 430 |
+
reward: Reward
|
| 431 |
+
done: bool
|
| 432 |
+
info: Dict
|
| 433 |
+
```
|
| 434 |
+
|
| 435 |
+
---
|
| 436 |
+
|
| 437 |
+
## π Project Structure
|
| 438 |
+
|
| 439 |
+
```
|
| 440 |
+
Data-cleaning/
|
| 441 |
+
βββ main.py # FastAPI server β all REST endpoints
|
| 442 |
+
βββ environment.py # DataCleaningEnv β reset/step/state + all ops
|
| 443 |
+
βββ models.py # Pydantic models β Action/Observation/Reward/StepResult
|
| 444 |
+
βββ inference.py # Baseline LLM agent β runs all tasks, outputs traces
|
| 445 |
+
βββ openenv.yaml # OpenEnv metadata β tasks, spaces, API config
|
| 446 |
+
βββ Dockerfile # Single-stage Python 3.10 container, port 7860
|
| 447 |
+
βββ README.md # This file
|
| 448 |
+
βββ baseline_results.json # Pre-run baseline scores (gpt-4o-mini)
|
| 449 |
+
βββ datasets/
|
| 450 |
+
βββ task_metadata.json # Task configs, allowed ops, scoring weights
|
| 451 |
+
βββ easy/
|
| 452 |
+
β βββ dirty.csv # Employee dataset with duplicates + bad column names
|
| 453 |
+
β βββ gold.csv # Ground truth
|
| 454 |
+
βββ medium/
|
| 455 |
+
β βββ dirty.csv # Customer dataset with missing values + wrong types
|
| 456 |
+
β βββ gold.csv
|
| 457 |
+
βββ hard/
|
| 458 |
+
β βββ dirty.csv # Orders dataset with all issue types
|
| 459 |
+
β βββ gold.csv
|
| 460 |
+
βββ expert/
|
| 461 |
+
βββ dirty.csv # Sales data with case normalization + full pipeline
|
| 462 |
+
βββ gold.csv
|
| 463 |
```
|
| 464 |
|
| 465 |
+
---
|
| 466 |
+
|
| 467 |
+
## π¬ Research Applications
|
| 468 |
+
|
| 469 |
+
This environment can be used to study:
|
| 470 |
+
|
| 471 |
+
- **Sequence learning in RL** β Can agents learn optimal operation ordering from reward signals alone?
|
| 472 |
+
- **Dense vs. sparse rewards** β Compare agent performance with/without the sequence penalties disabled
|
| 473 |
+
- **Tool use planning** β Does the agent build a plan before acting, or does it react greedily?
|
| 474 |
+
- **Generalization** β Train on easy/medium tasks, evaluate zero-shot on expert
|
| 475 |
+
- **LLM agent benchmarking** β Evaluate frontier models on a deterministic, math-graded task with no LLM-judge subjectivity
|
| 476 |
+
|
| 477 |
+
---
|
| 478 |
+
|
| 479 |
+
## π Links
|
| 480 |
+
|
| 481 |
+
| Resource | URL |
|
| 482 |
+
|---|---|
|
| 483 |
+
| π Live Demo (UI) | https://thorodin103-data-cleaning.hf.space/ui |
|
| 484 |
+
| π€ HuggingFace Space | https://huggingface.co/spaces/thorodin103/Data-cleaning/tree/main |
|
| 485 |
+
| β
OpenEnv Validate | https://thorodin103-data-cleaning.hf.space/validate |
|
| 486 |
+
| π API Docs (Swagger) | https://thorodin103-data-cleaning.hf.space/docs |
|
| 487 |
+
| π Task List | https://thorodin103-data-cleaning.hf.space/tasks |
|
| 488 |
+
| π
Leaderboard | https://thorodin103-data-cleaning.hf.space/leaderboard |
|
| 489 |
+
|
| 490 |
+
---
|
| 491 |
+
|
| 492 |
+
## π License
|
| 493 |
+
|
| 494 |
+
MIT β free for research and commercial use.
|
| 495 |
+
|
| 496 |
+
---
|
| 497 |
|
| 498 |
+
*Built for the OpenEnv Hackathon. Powered by FastAPI + Pandas + Pydantic + Hugging Face Spaces.*
|
|
|
|
|
|