学習者言語の分析(基礎)2(第6回)

  • 6.1 特徴量
  • 6.2 特徴量選択
    • 6.2.1 変動係数
    • 6.2.2 スコアとの相関
    • 6.2.3 特徴量同士の相関係数
In [1]:
# 使用するパッケージのimport
import os
import numpy as np
from scipy.stats import mode
import pandas as pd
from nltk import word_tokenize,sent_tokenize
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.naive_bayes import GaussianNB
from sklearn.naive_bayes import MultinomialNB
from sklearn.neighbors import KNeighborsClassifier
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

import spacy
from spacy import displacy
nlp = spacy.load("en_core_web_sm")

6.1 特徴量¶

  • これまでの授業で扱った特徴量は以下です。
    1. 総文数
    2. 総語数
    3. Type Token Ratio (TTR)
    4. 1文あたりの平均語数
    5. 単語の出現回数に基づいたベクトル表現
    6. 依存文法に基づいた文法項目に関する特徴量(1文あたりの節数と名詞句の平均語数)
    7. 品詞の頻度に基づいた特徴量
    8. 語彙の多様性に関する特徴量
    9. 語彙の洗練度に関する特徴量
  • これまでの練習問題で使用したコーパスを用いて特徴量を抽出してみましょう。
In [3]:
# 対象とするテキストファイルの読み込み

fnames = os.listdir("../DATA02/NICE_NNS2/")

## ファイル名をソート ##
fnames.sort()

T = []

for i in fnames:
    f = open("../DATA02/NICE_NNS2/"+i,"r")
    text = f.read()
    f.close()
    T.append(text)
  • 以下の関数を用いて1から4の特徴量を抽出します。
In [4]:
def feature_count(X):
    s = len(sent_tokenize(X))
    tokens = word_tokenize(X)
    w = len(tokens)
    types = len(list(set(tokens)))
    ttr = types / w
    wps = w / s
    F = [s,w,ttr,wps]
    return F
In [5]:
Features_1 = []

for i in T:
    j = feature_count(i)
    Features_1.append(j)
  • 総文数、総語数、Type token ratio(異なり語の割合)、1文あたりの平均語数の順にリストになっています。
In [6]:
Features_1[0]
Out[6]:
[25, 392, 0.44387755102040816, 15.68]
  • 「5. 単語の出現回数に基づいたベクトル表現」に関しては、あとで抽出します。
    1. の「1文あたりの節数」と「名詞句の平均語数」を抽出します。
In [10]:
CLAUSE = ["advcl","relcl","ccomp","csubj"]

CpS = []

for i in T:
    c = 0
    sents = sent_tokenize(i)
    s = len(sents)
    for j in sents:
        doc = nlp(j)
        for token in doc:
            if token.dep_ in CLAUSE:
                c +=1
    CpS.append(c/s)
    
In [11]:
NL = []

for i in T:
    tmp = []
    sents = sent_tokenize(i)
    for j in sents:
        doc = nlp(j)
        for chunk in doc.noun_chunks:
            tmp.append(len(chunk.text.split()))
    NL.append(sum(tmp)/len(tmp))
  • 総文数、総語数、Type token ratio(異なり語の割合)、1文あたりの平均語数、1文あたりの節数、名詞句の平均語数をひとつのリストにまとめます。
In [12]:
X = []

for i,j,k in zip(Features_1,CpS,NL):
    x = i + [j] + [k]
    X.append(x)
In [13]:
X[0]
Out[13]:
[25, 392, 0.44387755102040816, 15.68, 0.28, 1.8144329896907216]

6.2 特徴量選択¶

  • これまでの授業では特徴量の抽出→自動採点の流れにおいて特徴量の選択に関して検討してきませんでした。
  • どの特徴量を予測に使用するかを検討することで、自動採点の解釈可能性が上がる場合があります。
  • 自動採点においてスコアを予測する特徴量を選択する方法はいくつかありますが、ここでは、フィルター法の一部を取り入れて特徴量を選択します。
  • ここでは、以下を検討における指標とします。
    • 変動係数
    • スコアと特徴量の相関係数
    • 特徴量同士の相関係数

6.2.1 変動係数¶

  • 特徴量にある程度ばらつきがないとスコアの予測には使用できません。
  • 極端な例として、すべてのデータが1であるものは予測に使えません。
  • すべてのデータが同じ値でなくてもばらつきが小さいデータは予測に有用ではありません。
  • 標準偏差というデータのばらつきを示す統計量がありますが、これは、データがとりうる値によって大きく変わります。
  • そのため、標準偏差を平均値で割って平均値に対するデータとばらつきの関係を相対的に評価する統計量を用います。
  • 変動係数を用いることでデータ同士のばらつきを比較することができます。
In [14]:
# スコアの読み込み
Eva = pd.read_csv("../DATA02/nice_evaluation.csv",index_col=0)
Y = list(Eva["score"])
In [15]:
# 上でリストに保存した特徴量をデータフレームに保存
data = pd.DataFrame(X,columns=["sents","words","TTR","WPS","CPS","NPL"])
data.head()
Out[15]:
sents words TTR WPS CPS NPL
0 25 392 0.443878 15.680000 0.280000 1.814433
1 18 288 0.350694 16.000000 0.611111 1.931507
2 26 548 0.452555 21.076923 0.884615 1.784722
3 21 332 0.400602 15.809524 0.809524 1.365385
4 18 391 0.493606 21.722222 1.166667 1.690000
  • 変動係数(CV)は以下で求められます。
$$CV = \frac{標準偏差}{平均}$$
In [16]:
# それぞれの特徴量の変動係数を計算
CV = []

for i in data.columns:
    cv = data[i].std()/data[i].mean()
    CV.append(cv)
In [17]:
# 算出した変動係数をデータフレームに保存
data_cv = pd.DataFrame([CV],columns=data.columns,index=["CV"])
data_cv
Out[17]:
sents words TTR WPS CPS NPL
CV 0.373414 0.37209 0.14136 0.258507 0.434414 0.101353
  • 名詞句の平均語数(NPL)の変動係数が最も小さい。

6.2.2 スコアとの相関¶

  • 特徴量とスコアとの相関係数を計算します。
  • この相関係数が低い特徴量はスコアの予測には寄与しない可能性が高いです。
In [18]:
CC = []

for i in data.columns:
    cc = np.corrcoef(Y,data[i].values)[0][1]
    CC.append(cc)
In [19]:
data_cc = pd.DataFrame([CC],columns=data.columns,index=["CC"])
data_cc
Out[19]:
sents words TTR WPS CPS NPL
CC 0.282074 0.697879 -0.301265 0.570192 0.36007 0.289299
  • スコアと総文数との相関係数が最も低い。

6.2.3 特徴量同士の相関係数¶

  • 抽出した特徴量は「作文における英語の能力」の部分と仮定しているので、他の特徴量との相関係数が低い特徴量はこの「作文における英語の能力」とは関係ない能力に関する特徴量であるか、あるいは、抽出がうまくいってない可能性があります。
In [20]:
data.corr()
Out[20]:
sents words TTR WPS CPS NPL
sents 1.000000 0.714656 -0.566967 -0.290585 -0.278658 -0.086715
words 0.714656 1.000000 -0.581803 0.417961 0.245815 0.237285
TTR -0.566967 -0.581803 1.000000 -0.083262 -0.185807 -0.001388
WPS -0.290585 0.417961 -0.083262 1.000000 0.714217 0.445935
CPS -0.278658 0.245815 -0.185807 0.714217 1.000000 0.017773
NPL -0.086715 0.237285 -0.001388 0.445935 0.017773 1.000000
  • 以下では、データフレームにスコアを追加し、スコアごとにプロットしています。
In [21]:
data_corr = data
data_corr["score"] = Y
data_corr.head()
Out[21]:
sents words TTR WPS CPS NPL score
0 25 392 0.443878 15.680000 0.280000 1.814433 3
1 18 288 0.350694 16.000000 0.611111 1.931507 3
2 26 548 0.452555 21.076923 0.884615 1.784722 5
3 21 332 0.400602 15.809524 0.809524 1.365385 3
4 18 391 0.493606 21.722222 1.166667 1.690000 3
In [22]:
sns.pairplot(data_corr,hue="score",plot_kws=dict(alpha=0.4),palette="viridis")
Out[22]:
<seaborn.axisgrid.PairGrid at 0x7e04d0312e10>