Dhruv Goyal commited on
Commit
f0ad703
Β·
1 Parent(s): 782a588

fix: add HF Space metadata + full docs

Browse files
Files changed (1) hide show
  1. README.md +152 -59
README.md CHANGED
@@ -1,68 +1,161 @@
1
- # Data Cleaning & ETL OpenEnv Environment
2
-
3
- This environment simulates a real-world data cleaning and ETL pipeline task where an AI agent must clean messy CSV/Excel data through a series of operations. It is designed for training and evaluating reinforcement learning agents on data preparation tasks.
4
-
5
- ## Motivation
6
-
7
- Data cleaning is a common, time-consuming task in data science and analytics. Automating it with AI can save significant time and reduce errors. This environment provides a structured way to train agents to perform typical data cleaning operations: fixing nulls, correcting data types, removing duplicates, normalizing values, merging tables, and more.
8
-
9
- ## Action and Observation Spaces
10
-
11
- ### Actions
12
- Each action is a JSON object with an `operation` field and other fields as needed.
13
-
14
- - `fill_nulls`: Fill missing values in a column.
15
- - Required: `column`, `strategy` (`mean`, `median`, `mode`, `constant`, `forward_fill`, `backward_fill`)
16
- - Optional: `value` (for constant fill)
17
- - `cast_column`: Change data type.
18
- - Required: `column`, `dtype` (`int`, `float`, `str`, `datetime`)
19
- - `remove_duplicates`: Remove duplicate rows.
20
- - Optional: `subset` (list of columns), `keep` (`first`, `last`, `false`)
21
- - `normalize_values`: Normalize string values.
22
- - Required: `column`, `method` (`lower`, `upper`, `regex`)
23
- - For regex: `pattern`, `replacement`
24
- - `filter_outliers`: Remove outliers based on z-score.
25
- - Required: `column`, `method` (`zscore`)
26
- - Optional: `threshold` (default 3.0)
27
- - `merge_tables`: Join two tables.
28
- - Required: `left_table`, `right_table`, `on`
29
- - Optional: `how` (`inner`, `left`, `right`, `outer`), `output_table`
30
- - `add_derived_column`: Create a new column from an existing one.
31
- - Required: `column_name`, `source_column`, `transform` (`year_from_date`, `log1p`, `abs`, `len`, `upper`, `lower`)
32
- - `submit`: End episode.
33
-
34
- ### Observations
35
- Observations provide:
36
- - Task description and progress (step count, max steps)
37
- - Current state of tables (head, dtypes, null counts, duplicates, row counts)
38
- - Reward and done flag
39
- - Partial score (current grader score)
40
 
41
  ## Tasks
42
 
43
- 1. **Easy: Null Fixer**
44
- - Fix nulls and data types in a 50-row customer dataset (age as string, salary nulls).
45
- - Expected: age integer, salary integer, no nulls.
46
- - Max steps: 10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- 2. **Medium: Schema Normalizer**
49
- - Clean a 200-row orders dataset: remove duplicates, normalize country names (USA/usa/U.S.A β†’ US), fix date format (YYYY/MM/DD β†’ YYYY-MM-DD), fill null amounts.
50
- - Max steps: 20
 
 
51
 
52
- 3. **Hard: ETL Pipeline**
53
- - Join orders and customers tables (400 orders, 100 customers), remove outliers in amount (z-score >3), add a derived column `year` from date.
54
- - Max steps: 30
55
 
56
- ## Setup and Usage
57
 
58
- ### Local Development
59
- 1. Clone the repository.
60
- 2. Install dependencies: `pip install -r requirements.txt`
61
- 3. Run the server: `uvicorn server.app:app --reload --port 7860`
62
- 4. Interact with the environment using HTTP requests or the OpenEnv client.
 
 
 
 
 
 
 
 
 
 
63
 
64
- ### Docker
65
- Build and run:
66
  ```bash
67
- docker build -t dataclean-env ./server
68
- docker run -p 7860:7860 dataclean-env
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Dataclean Env
3
+ emoji: 🧹
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: docker
7
+ pinned: false
8
+ tags:
9
+ - openenv
10
+ - data-cleaning
11
+ - etl
12
+ - real-world
13
+ - tabular
14
+ - data-drift
15
+ - streaming
16
+ ---
17
+
18
+ # DataClean OpenEnv
19
+
20
+ A **real-world data cleaning and ETL environment** for AI agent RL training, built on the [OpenEnv](https://meta-pytorch.org/OpenEnv/) framework by Meta-PyTorch and Hugging Face.
21
+
22
+ Agents learn to fix messy tabular data β€” filling nulls, normalising inconsistent values, removing duplicates, filtering outliers, performing multi-table ETL joins, and handling **live data drift** (novel: fresh dirty rows injected mid-episode every 5 steps).
23
+
24
+ ---
25
+
26
+ ## Why This Environment
27
+
28
+ Data cleaning is one of the most common, time-consuming tasks in real data engineering. Every company with a data pipeline does this daily. Training an RL agent on this task has immediate real-world value β€” unlike game-based environments.
29
+
30
+ **What makes this different from other OpenEnv submissions:**
31
+ - Task 4 (Data Drift) is genuinely novel β€” no existing OpenEnv environment simulates live streaming row injection mid-episode
32
+ - Parallel baseline using `concurrent.futures.ThreadPoolExecutor` β€” all 4 tasks run simultaneously
33
+ - Deterministic graders using seeded dataset generation β€” perfectly reproducible scores
34
+ - Dense reward signal: reward = grader(new_state) βˆ’ grader(prev_state) at every step
35
+
36
+ ---
 
 
 
37
 
38
  ## Tasks
39
 
40
+ | Task | Difficulty | Description | Max Steps |
41
+ |------|-----------|-------------|-----------|
42
+ | `task1` | Easy | Fix nulls + dtypes in 50-row customer CSV | 10 |
43
+ | `task2` | Medium | Dedup + normalize strings + fix dates + fill nulls | 20 |
44
+ | `task3` | Hard | Multi-table merge + outlier removal + derived column | 30 |
45
+ | `task4_data_drift` | **Expert** | Live streaming table β€” 7 dirty rows injected every 5 steps | 40 |
46
+
47
+ ---
48
+
49
+ ## Action Space
50
+
51
+ Every action is a JSON object with an `operation` field:
52
+
53
+ ```json
54
+ {"operation": "fill_nulls", "column": "age", "strategy": "median"}
55
+ {"operation": "cast_column", "column": "age", "dtype": "int"}
56
+ {"operation": "remove_duplicates"}
57
+ {"operation": "normalize_values", "column": "country", "method": "upper"}
58
+ {"operation": "cast_column", "column": "order_date", "dtype": "datetime"}
59
+ {"operation": "filter_outliers", "column": "amount", "method": "iqr", "threshold": 1.5}
60
+ {"operation": "merge_tables", "left_table": "orders", "right_table": "customers", "on": "customer_id", "output_table": "merged"}
61
+ {"operation": "add_derived_column", "column_name": "order_year", "source_column": "order_date", "transform": "year_from_date", "table_name": "merged"}
62
+ {"operation": "submit"}
63
+ ```
64
+
65
+ ## Observation Space
66
+
67
+ After each `reset()` / `step()` the agent receives:
68
+
69
+ - `task_id`, `task_description`, `step_count`, `max_steps`, `message`
70
+ - `tables` β€” dict of `{table_name β†’ JSON string of df.head(10)}`
71
+ - `column_dtypes`, `null_counts`, `duplicate_count`, `row_count`
72
+ - `schema_errors` β€” list of detected problems to guide the agent
73
+ - `reward`, `done`, `partial_score` β€” RL signals
74
+
75
+ ---
76
+
77
+ ## Reward Function
78
 
79
+ ```
80
+ step_reward = grader(current_state) βˆ’ grader(previous_state) # dense delta signal
81
+ invalid_op = βˆ’0.02 # bad operation penalty
82
+ terminal = final grader score on submit or max_steps
83
+ ```
84
 
85
+ Partial credit per sub-dimension. Score range: `[0.0, 1.0]`.
 
 
86
 
87
+ ---
88
 
89
+ ## Baseline Scores (llama-3.3-70b-versatile, seed=42, parallel run)
90
+
91
+ | Task | Score | Time |
92
+ |------|-------|------|
93
+ | task1 (easy) | 1.0000 | 11.8s |
94
+ | task2 (medium) | 1.0000 | 34.1s |
95
+ | task3 (hard) | 0.8000 | 22.4s |
96
+ | task4_data_drift (expert) | 0.9297 | 26.6s |
97
+ | **mean** | **0.9324** | **34.3s wall** |
98
+
99
+ All 4 tasks run in parallel β€” wall time = slowest task, not sum.
100
+
101
+ ---
102
+
103
+ ## Setup & Local Run
104
 
 
 
105
  ```bash
106
+ pip install -r requirements.txt
107
+ uvicorn server.app:app --host 0.0.0.0 --port 7860 --reload
108
+ ```
109
+
110
+ ```bash
111
+ curl http://localhost:7860/health
112
+ curl http://localhost:7860/tasks
113
+ ```
114
+
115
+ ```bash
116
+ export OPENAI_API_KEY=your_key
117
+ export OPENAI_BASE_URL=https://api.groq.com/openai/v1
118
+ export BASELINE_MODEL=llama-3.3-70b-versatile
119
+ python baseline.py
120
+ ```
121
+
122
+ ## Docker
123
+
124
+ ```bash
125
+ docker build -t dataclean-env .
126
+ docker run -p 7860:7860 -e OPENAI_API_KEY=your_key dataclean-env
127
+ ```
128
+
129
+ ---
130
+
131
+ ## API Endpoints
132
+
133
+ | Method | Endpoint | Description |
134
+ |--------|----------|-------------|
135
+ | POST | `/reset` | Start new episode |
136
+ | POST | `/step` | Execute one cleaning operation |
137
+ | GET | `/state` | Current episode metadata |
138
+ | GET | `/tasks` | All tasks + action schema |
139
+ | GET | `/grader` | Score current episode state |
140
+ | GET | `/baseline` | Run baseline agent on all tasks |
141
+ | GET | `/health` | Liveness probe |
142
+ | GET | `/docs` | Interactive Swagger UI |
143
+
144
+ ---
145
+
146
+ ## Project Structure
147
+
148
+ ```
149
+ dataCleaningProject/
150
+ β”œβ”€β”€ server/
151
+ β”‚ β”œβ”€β”€ app.py # FastAPI server β€” all endpoints
152
+ β”‚ β”œβ”€β”€ environment.py # Core env logic β€” reset/step/state + drift injection
153
+ β”‚ β”œβ”€β”€ graders.py # Deterministic scoring for all 4 tasks
154
+ β”‚ └── dataset_factory.py # Seeded dirty+expected dataset generation + drift batches
155
+ β”œβ”€β”€ models.py # Pydantic Action + Observation models
156
+ β”œβ”€β”€ baseline.py # Parallel baseline (ThreadPoolExecutor, 4 tasks at once)
157
+ β”œβ”€β”€ client.py # HTTP client
158
+ β”œβ”€β”€ openenv.yaml # OpenEnv manifest
159
+ β”œβ”€β”€ Dockerfile # Port 7860, Python 3.11-slim
160
+ └── requirements.txt
161
+ ```