Spaces:
Sleeping
Sleeping
File size: 6,531 Bytes
508bc3b | 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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | ---
title: Data Cleaning Environment
emoji: π§Ή
colorFrom: blue
colorTo: green
sdk: docker
app_port: 8000
base_path: /web
---
# Data Cleaning Environment
A real-world OpenEnv environment where an AI agent learns to clean tabular data
through the standard `step()` / `reset()` / `state()` API.
The agent receives a dirty CSV-style dataset and must apply cleaning operations
step-by-step to maximise a data-quality score (0.0 β 1.0).
---
## Tasks
| Task ID | Difficulty | Description | Max Steps |
|----------|------------|-----------------------------------------------------------------|-----------|
| `easy` | Easy | Fix 3 missing values (name / age) in a 5-row table | 10 |
| `medium` | Medium | Remove 2 duplicate rows **and** fix 2 type errors in `age` | 15 |
| `hard` | Hard | Full pipeline: missing values + duplicates + outliers + normalise text | 25 |
---
## Action Space
```json
{
"operation": "<string>",
"column": "<string | null>"
}
```
| Operation | Task(s) | Effect |
|---------------------|------------------|-----------------------------------------------------|
| `impute_mean` | easy | Fill numeric `None` with column mean |
| `impute_mode` | easy | Fill string `None` with column mode |
| `drop_missing_rows` | easy / medium | Drop all rows containing any `None` |
| `remove_duplicates` | medium | Drop exact-duplicate rows |
| `fix_type_errors` | medium | Coerce non-numeric values to `float` (or `None`) |
| `remove_outliers` | hard | Drop rows where `price β€ 0` or `price β₯ 500` |
| `normalize_text` | hard | Strip whitespace + title-case all string columns |
| `fill_quantity_mean`| hard | Fill missing `quantity` with column mean |
---
## Observation Space
| Field | Type | Description |
|-------------------|---------|-----------------------------------------------------------|
| `current_text` | `str` | Human-readable table of current rows |
| `is_normalized` | `bool` | True when no missing values, duplicates, or outliers left |
| `remaining_typos` | `int` | Composite issue count (missing + dupes + outliers) |
| `html_found` | `bool` | Always `False` (compatibility field) |
| `done` | `bool` | Episode ended (score=1.0 or step limit reached) |
| `reward` | `float` | Ξ quality score from this step (partial progress signal) |
| `metadata` | `dict` | Full row data, per-field diagnostics, valid ops list |
---
## Reward Function
```
reward = (quality_score_after - quality_score_before) + 0.01 # if improvement
reward = (quality_score_after - quality_score_before) - 0.01 # if no improvement
```
Each task has its own grader:
- **Easy**: fraction of the 3 original missing values that are resolved
- **Medium**: average of (dedup score, type-fix score)
- **Hard**: average of 4 sub-scores (no missing, no dupes, no outliers, normalised text)
Invalid operations incur a β0.05 penalty but do **not** end the episode.
---
## Baseline Scores
Deterministic rule-based agent (reproducible, seed=42):
| Task | Score |
|--------|-------|
| easy | 1.0 |
| medium | 1.0 |
| hard | 1.0 |
---
## API Endpoints
| Method | Path | Description |
|--------|-------------|--------------------------------------------------|
| POST | `/reset` | Start new episode. Body: `{"task":"easy"}` |
| POST | `/step` | Apply action. Body: `{"action":{...}}` |
| GET | `/state` | Current episode state |
| GET | `/schema` | Action + Observation JSON schemas |
| GET | `/tasks` | Task list + action schema per difficulty |
| POST | `/grader` | Score the current episode (0.0β1.0) |
| POST | `/baseline` | Run baseline agent on all 3 tasks |
| GET | `/health` | Health check |
| WS | `/ws` | WebSocket for low-latency persistent sessions |
---
## Quick Start
### 1. Reset to a task
```bash
curl -X POST http://localhost:8000/reset \
-H "Content-Type: application/json" \
-d '{"task": "easy"}'
```
### 2. Apply a cleaning operation
```bash
curl -X POST http://localhost:8000/step \
-H "Content-Type: application/json" \
-d '{"action": {"operation": "impute_mean"}}'
```
### 3. Get current state
```bash
curl http://localhost:8000/state
```
### 4. Score the episode
```bash
curl -X POST http://localhost:8000/grader
```
### 5. Run baseline on all tasks
```bash
curl -X POST http://localhost:8000/baseline
```
---
## Setup
### Run locally
```bash
uv run server
# or
uvicorn server.app:app --reload --host 0.0.0.0 --port 8000
```
### Run with Docker
```bash
docker build -t data-cleaning-env:latest -f server/Dockerfile .
docker run -p 8000:8000 data-cleaning-env:latest
```
### Deploy to Hugging Face Spaces
```bash
openenv push --repo-id your-username/data-cleaning-env
```
---
## Project Structure
```
data_cleaning_env/
βββ README.md # This file
βββ openenv.yaml # OpenEnv manifest
βββ pyproject.toml # Project metadata & dependencies
βββ uv.lock # Locked dependencies
βββ models.py # Action + Observation Pydantic models
βββ client.py # DataCleaningEnv HTTP/WS client
βββ server/
βββ app.py # FastAPI app + /tasks /grader /baseline
βββ data_cleaning_env_environment.py # Core environment logic + graders
βββ Dockerfile # Container image
```
---
## Dependencies
- `openenv-core[core] >= 0.2.2` β OpenEnv runtime
- Python 3.10+
- No external data dependencies β all datasets are generated synthetically at runtime |