File size: 3,529 Bytes
e71990c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import re
import ray
import numpy as np
import pandas as pd 
from ray.data import Dataset
from sklearn.model_selection import train_test_split
from src.config import STOPWORDS 
from typing import Dict,List,Tuple
from transformers import BertTokenizer

def data(dataset_loc: str, num_samples: int = None) -> ray.data.Dataset:
    dataset = ray.data.read_csv(dataset_loc)
    dataset = dataset.random_shuffle(seed = 1234)
    dataset = ray.data.from_items(dataset.take(num_samples)) if num_samples else dataset
    return dataset

def stratify_split(
        ds: Dataset, 
        stratify: str, 
        test_size: float, 
        shuffle: bool = True,
        seed: int = 1234,
) -> Tuple[Dataset, Dataset]: 
    def _add_split(df: pd.DataFrame) -> pd.DataFrame:
        train, test = train_test_split(df, test_size=test_size, shuffle=shuffle, random_state=seed)
        train["_split"]= "train"
        test["_split"] = "test"
        return pd.concat([train,test])
    
    def _filter_split(df: pd.DataFrame, split: str) -> pd.DataFrame:
        return df[df["_split"] == split].drop("_split", axis = 1)
    
    grouped = ds.groupby(stratify).map_groups(_add_split, batch_format="pandas")
    train_ds = grouped.map_batches(_filter_split, fn_kwargs={"split":"train"}, batch_format="pandas")
    test_ds = grouped.map_batches(_filter_split, fn_kwargs={"split":"test"}, batch_format="pandas")

    train_ds = train_ds.random_shuffle(seed=seed)
    test_ds = test_ds.random_shuffle(seed=seed)

    return train_ds, test_ds

def clean_text(text: str) -> str:
    # change every words into lower case
    text = text.lower()

    text = re.sub(r"http\S+", "", text) # remove links (must run before punctuation gets spaced apart below)

    # removing stopwords such as "is", "the" and so on
    pattern = re.compile(r'\b(' + r"|".join(STOPWORDS)+ r")\b\s*")
    text = pattern.sub('', text)

    text = re.sub(r"([!\"'#$%&()*\+,-./:;<=>?@\\\[\]^_`{|}~])", r" \1 ", text) # add space
    text = re.sub("[^A-Za-z0-9]+", " ", text) # remove other than words and numbers
    text = re.sub(" +", " ", text) # remove all extra spaces
    text = text.strip() # remove spaces at the start and at the end

    return text

_tokenizer_cache = {}

def _get_tokenizer(model_name: str = "allenai/scibert_scivocab_uncased"):
    # cache per-process so map_batches workers don't reload the tokenizer on every batch
    if model_name not in _tokenizer_cache:
        _tokenizer_cache[model_name] = BertTokenizer.from_pretrained(model_name, return_dict=False)
    return _tokenizer_cache[model_name]

def tokenize(batch: Dict) -> Dict:
    tokenizer = _get_tokenizer()
    encoded = tokenizer(batch["text"].tolist(), return_tensors="np", padding = "longest")
    return dict(ids=encoded["input_ids"], masks=encoded["attention_mask"], targets=np.array(batch["label"]))

def preprocess(df: pd.DataFrame):
    df["text"] = df.text.apply(clean_text)
    targets = tokenize(df)
    return targets 

class CustomPreprocessor():
    """Custom Preprocess."""
    def __init__(self, label_decoder = None):
        self.label_decoder = label_decoder or {
            0: "World",
            1: "Sports",
            2: "Business",
            3: "Sci/Tech"
        }
        self.class_to_index = {v:k for k, v in self.label_decoder.items()}

    def fitting(self, ds):
        _ = ds.unique(column="label")
        return self
    
    def transforming(self, ds):
        return ds.map_batches(
            preprocess, 
            batch_format = "pandas")