データ加工について

# 前処理：

## 単語の正規化：

### モジュール・ライブラリのインポート

```python
import re
import unicodedata
import neologdn
import nltk
from nltk.corpus import wordnet
```

### 実際に使えるように関数化

```python
def normalize(text):
    normalized_text = neologdn_normalize(text)
    normalized_text = normalize_unicode(normalized_text)
    normalized_text = normalize_number(normalized_text)
    normalized_text = lower_text(normalized_text)
    return normalized_text

def neologdn_normalize(text):
    normalized_text = neologdn.normalize(text)
    return normalized_text

def lower_text(text):
    return text.lower()

def normalize_unicode(text, form='NFKC'):
    normalized_text = unicodedata.normalize(form, text)
    return normalized_text

def lemmatize_term(term, pos=None):
    if pos is None:
        synsets = wordnet.synsets(term)
        if not synsets:
            return term
        pos = synsets[0].pos()
        if pos == wordnet.ADJ_SAT:
            pos = wordnet.ADJ
    return nltk.WordNetLemmatizer().lemmatize(term, pos=pos)

def normalize_number(text):
    """
    pattern = r'\d+'
    replacer = re.compile(pattern)
    result = replacer.sub('0', text)
    """

    replaced_text = re.sub(r'\d+', '0', text)
    return replaced_text
```

## ストップワーズの指定：

```python
from urllib.request import urlopen
slothlib_path = 'http://svn.sourceforge.jp/svnroot/slothlib/CSharp/Version1/SlothLib/NLP/Filter/StopWord/word/Japanese.txt'
slothlib_file = urlopen(slothlib_path)
slothlib_stopwords = [line.decode("utf-8").strip() for line in slothlib_file]
slothlib_stopwords = [ss for ss in slothlib_stopwords if not ss==u'']
```

# 後処理：

## 次元削減：

次元削減とは、扱うデータの次元が大きすぎて扱えない場合に、扱える範囲まで次元削減の処理を行う必要がある。

### モジュール・ライブラリのインポート

```python
from sklearn.decomposition import TruncatedSVD
```

### 実際に使えるように関数化

```python
def reduce_dimension(tfv_vector): 
    lsa = TruncatedSVD(n_components=500,n_iter=5, random_state = 0) # 今回は次元数を500に指定
    lsa.fit(tfv_vector) 
    tfv_vector_lsa = lsa.transform(tfv_vector)
    return tfv_vector_lsa
```

## ベクトルの正規化：

ここでは、最小値0、最大値1に正規化したいため、MinMaxScalerクラスを使う

※ MinMaxScalerクラスでは一次元配列は処理されず、二次元配列のみが対象。列ごとに正規化され、行ごとや全体に対する処理はできない。

### モジュール・ライブラリのインポート

```python
from sklearn import preprocessing
```

### 実際に使えるように関数化

```python
def normalize_vector(tfv_vector_lsa):
    mm = preprocessing.MinMaxScaler()
    tfv_vector_lsa = mm.fit_transform(tfv_vector_lsa)
    return tfv_vector_lsa
```

## サンプリング手法：

不均一データに対する処理としてサンプリング手法が挙げられます。

- アンダーサンプリングとは、数が少ないデータを一定の数に増やすといったものです
- オーバーサンプリングとは、数が多いデータを一定の数に減らすといったものです。

### モジュール・ライブラリのインポート

```python
from imblearn.under_sampling import RandomUnderSampler
from imblearn.over_sampling import RandomOverSampler
```

### 実際に使えるように関数化

```python
#アンダーサンプリング
def under_sampling(x_train, y_train, strategy):
    rus = RandomUnderSampler(random_state=0, sampling_strategy = strategy)
    x_resampled, y_resampled = rus.fit_resample(x_train, y_train)
    return x_resampled, y_resampled

#オーバーサンプリング
def over_sampling(x_train, y_train, strategy):
    ros = RandomOverSampler(random_state=0,sampling_strategy = strategy)
    x_resampled, y_resampled = ros.fit_sample(x_train, y_train)
    return x_resampled, y_resampled
```

### コードについての補足

引数として、strategyを設定しているが、以下のように設定することができる。

```python
strategy = {0:50, 1:50, 2:100, 3:100, 10:100}
```

## 訓練データとテストデータを分ける：

データを学習するための訓練データとテストデータに分ける方法は以下のようになる。

### モジュール・ライブラリのインポート

```python
from sklearn.model_selection import train_test_split
```

### 実際に使えるように関数化

```python
def split_data(x_data, y_data):
    x_train, x_test, y_train, y_test = train_test_split(x_data, y_data, test_size=0.2, random_state=100,stratify=y_data)  
    return  x_train, x_test, y_train, y_test
```

# 参考文献：

- [機械学習_サポートベクターマシーン_pythonで実装](https://dev.classmethod.jp/articles/2017ad_20171214_svm_python/#toc-5)
- [Pythonで正規化・標準化（リスト、NumPy配列、pandas.DataFrame）](https://note.nkmk.me/python-list-ndarray-dataframe-normalize-standardize/)
- [imbalanced-learn を使ってアンダーサンプリングをしてみた](https://qiita.com/yuki_edy/items/eb5a0c36abea08ba0aeb)