Spaces:
Runtime error
Runtime error
| import json | |
| from pathlib import Path | |
| from typing import Any, Dict, List | |
| import numpy as np | |
| import pandas as pd | |
| from datasets import Dataset, DatasetDict | |
| from sklearn.model_selection import train_test_split | |
| from transformers import AutoTokenizer | |
| from absa.data.bio_tagger import convert_to_bio | |
| np.random.seed(42) | |
| def load_data(file_paths: List[Path]) -> List[Dict[str, Any]]: | |
| data = [] | |
| for path in file_paths: | |
| with open(path, "r", encoding="utf-8") as f: | |
| for line in f: | |
| if line.strip(): | |
| data.append(json.loads(line)) | |
| return data | |
| def prepare_ner_data(data: List[Dict[str, Any]]) -> List[Dict[str, Any]]: | |
| """Prepares data for Token Classification (NER).""" | |
| ner_data: List[Dict[str, Any]] = [] | |
| label_map = {"O": 0, "B-ASP": 1, "I-ASP": 2} | |
| for item in data: | |
| text = item["text"] | |
| aspects = item.get("aspect_terms", []) | |
| bio_tags = convert_to_bio(text, aspects) | |
| tokens = [t["token"] for t in bio_tags] | |
| ner_tags = [label_map[t["label"]] for t in bio_tags] | |
| ner_data.append( | |
| { | |
| "tokens": tokens, | |
| "ner_tags": ner_tags, | |
| "id": item.get("id", str(len(ner_data))), | |
| } | |
| ) | |
| return ner_data | |
| def prepare_cls_data(data: List[Dict[str, Any]]) -> List[Dict[str, Any]]: | |
| """Prepares data for Sequence Classification (Sentiment).""" | |
| cls_data: List[Dict[str, Any]] = [] | |
| sentiment_map = {"positive": 0, "negative": 1, "neutral": 2, "conflict": 3} | |
| for item in data: | |
| text = item["text"] | |
| aspects = item.get("aspect_terms", []) | |
| for aspect in aspects: | |
| term = aspect["term"] | |
| polarity = aspect["polarity"] | |
| if polarity not in sentiment_map: | |
| continue | |
| cls_data.append( | |
| { | |
| "text": text, | |
| "aspect_term": term, | |
| "label": sentiment_map[polarity], | |
| "id": f"{item.get('id', str(len(cls_data)))}_{term}", | |
| } | |
| ) | |
| return cls_data | |
| def align_labels_with_tokens(labels, word_ids): | |
| new_labels = [] | |
| current_word = None | |
| for word_id in word_ids: | |
| if word_id is None: | |
| new_labels.append(-100) | |
| elif word_id != current_word: | |
| new_labels.append(labels[word_id]) | |
| current_word = word_id | |
| else: | |
| new_labels.append(-100) | |
| return new_labels | |
| def main(): | |
| data_dir = Path("data/processed") | |
| output_dir = Path("data/tokenized") | |
| output_dir.mkdir(parents=True, exist_ok=True) | |
| # Load all English SemEval data | |
| train_path = data_dir / "semeval_train.jsonl" | |
| test_path = data_dir / "semeval_test.jsonl" | |
| all_data = load_data([train_path, test_path]) | |
| # Prepare datasets | |
| ner_data = prepare_ner_data(all_data) | |
| cls_data = prepare_cls_data(all_data) | |
| tokenizer = AutoTokenizer.from_pretrained("xlm-roberta-base") | |
| # --------------------------------------------------------- | |
| # 1. Token Classification (NER) Dataset | |
| # --------------------------------------------------------- | |
| ner_df = pd.DataFrame(ner_data) | |
| # Split 80/10/10 | |
| # For NER, we don't have a single sentiment to stratify on easily, so random split | |
| train_ner, temp_ner = train_test_split(ner_df, test_size=0.2, random_state=42) | |
| val_ner, test_ner = train_test_split(temp_ner, test_size=0.5, random_state=42) | |
| def tokenize_and_align_labels(examples): | |
| tokenized_inputs = tokenizer( | |
| examples["tokens"], | |
| truncation=True, | |
| is_split_into_words=True, | |
| max_length=128, | |
| ) | |
| labels = [] | |
| for i, label in enumerate(examples["ner_tags"]): | |
| word_ids = tokenized_inputs.word_ids(batch_index=i) | |
| labels.append(align_labels_with_tokens(label, word_ids)) | |
| tokenized_inputs["labels"] = labels | |
| return tokenized_inputs | |
| ner_dataset = DatasetDict( | |
| { | |
| "train": Dataset.from_pandas(train_ner, preserve_index=False), | |
| "validation": Dataset.from_pandas(val_ner, preserve_index=False), | |
| "test": Dataset.from_pandas(test_ner, preserve_index=False), | |
| } | |
| ) | |
| tokenized_ner = ner_dataset.map( | |
| tokenize_and_align_labels, | |
| batched=True, | |
| remove_columns=["tokens", "ner_tags", "id"], | |
| ) | |
| tokenized_ner.save_to_disk(str(output_dir / "absa_ner_dataset")) | |
| print(f"NER Dataset saved to {output_dir / 'absa_ner_dataset'}") | |
| # --------------------------------------------------------- | |
| # 2. Sequence Classification (Sentiment) Dataset | |
| # --------------------------------------------------------- | |
| cls_df = pd.DataFrame(cls_data) | |
| # Stratified split 80/10/10 based on label | |
| train_cls, temp_cls = train_test_split(cls_df, test_size=0.2, random_state=42, stratify=cls_df["label"]) | |
| val_cls, test_cls = train_test_split(temp_cls, test_size=0.5, random_state=42, stratify=temp_cls["label"]) | |
| def tokenize_cls(examples): | |
| # Format: [CLS] text [SEP] aspect_term [SEP] | |
| return tokenizer( | |
| examples["text"], | |
| examples["aspect_term"], | |
| truncation=True, | |
| max_length=128, | |
| padding=False, | |
| ) | |
| cls_dataset = DatasetDict( | |
| { | |
| "train": Dataset.from_pandas(train_cls, preserve_index=False), | |
| "validation": Dataset.from_pandas(val_cls, preserve_index=False), | |
| "test": Dataset.from_pandas(test_cls, preserve_index=False), | |
| } | |
| ) | |
| tokenized_cls = cls_dataset.map(tokenize_cls, batched=True, remove_columns=["text", "aspect_term", "id"]) | |
| tokenized_cls.save_to_disk(str(output_dir / "absa_cls_dataset")) | |
| print(f"CLS Dataset saved to {output_dir / 'absa_cls_dataset'}") | |
| if __name__ == "__main__": | |
| main() | |