blob: 4a8d41aef4c45c2e5b269e4dd19aa9cb4789cfed [file]
#!/usr/bin/env python3
"""Prepare REDD dataset for TsFile vs Parquet benchmark.
REDD (Reference Energy Disaggregation Data Set):
- Household electricity usage from 6 buildings
- Each channel = 1 meter = 1 device
- Schema: TAG(building, meter), FIELD(power DOUBLE)
Download: http://redd.csail.mit.edu/
Extract low_freq data to --raw-dir.
Usage:
python3 prepare_redd.py --raw-dir ./raw/redd --out-dir ./prepared/redd
"""
import argparse
import csv
import json
import os
import sys
from pathlib import Path
def parse_channel_file(filepath, building, channel):
"""Parse a REDD channel .dat file. Format: timestamp power_value"""
rows = []
with open(filepath, "r") as f:
for line in f:
line = line.strip()
if not line:
continue
parts = line.split()
if len(parts) < 2:
continue
try:
ts = int(float(parts[0]))
power = float(parts[1])
rows.append((ts, building, channel, power))
except ValueError:
continue
return rows
def main():
parser = argparse.ArgumentParser(description="Prepare REDD dataset")
parser.add_argument("--raw-dir", required=True,
help="Path to extracted REDD low_freq data")
parser.add_argument("--out-dir", required=True,
help="Output directory for prepared CSV")
args = parser.parse_args()
raw_dir = Path(args.raw_dir)
out_dir = Path(args.out_dir)
out_dir.mkdir(parents=True, exist_ok=True)
if not raw_dir.exists():
print(f"Error: raw directory {raw_dir} does not exist", file=sys.stderr)
print("Download from http://redd.csail.mit.edu/ and extract low_freq data",
file=sys.stderr)
sys.exit(1)
all_rows = []
devices = set()
house_dirs = sorted(raw_dir.glob("house_*"))
if not house_dirs:
print(f"Error: no house_* directories found in {raw_dir}", file=sys.stderr)
sys.exit(1)
for house_dir in house_dirs:
building = house_dir.name # e.g., "house_1"
channel_files = sorted(house_dir.glob("channel_*.dat"))
print(f" {building}: {len(channel_files)} channels")
for cf in channel_files:
channel = cf.stem # e.g., "channel_1"
device_id = f"{building}_{channel}"
devices.add(device_id)
rows = parse_channel_file(cf, building, channel)
all_rows.extend(rows)
print(f" {channel}: {len(rows)} points")
# Sort by device (building+channel), then timestamp
all_rows.sort(key=lambda r: (r[1], r[2], r[0]))
# Write CSV
csv_path = out_dir / "data_sorted.csv"
print(f"\nWriting {len(all_rows)} rows to {csv_path}...")
with open(csv_path, "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["timestamp", "building", "meter", "power"])
writer.writerows(all_rows)
# Write metadata
meta = {
"dataset": "redd",
"table_name": "redd",
"total_points": len(all_rows),
"num_devices": len(devices),
"num_series": len(devices), # 1 series per device
"tags": [
{"name": "building", "type": "STRING"},
{"name": "meter", "type": "STRING"},
],
"fields": [
{"name": "power", "type": "DOUBLE"},
],
}
meta_path = out_dir / "meta.json"
with open(meta_path, "w") as f:
json.dump(meta, f, indent=2)
print(f"Done: {meta['total_points']} points, "
f"{meta['num_devices']} devices, "
f"{meta['num_series']} series")
print(f" CSV: {csv_path}")
print(f" Meta: {meta_path}")
if __name__ == "__main__":
main()