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

  • 4.2 依存関係に関する特徴量を抽出する
    • 4.2.1 節の抽出
    • 4.2.2 名詞句の抽出
  • 4.3 依存関係に関する特徴量を用いた自動採点
  • 練習問題

4.2 依存関係に関する特徴量を抽出する¶

  • 先述の通り、これまで扱ってきた特徴量はかなり単純なものでした。
  • それでも英語母語話者と学習者を弁別することはかなりの程度可能でした。
  • これまで、1文あたりの平均的語数(Words per sentence)を利用してきましたが、以下のような問題があります。

a. The athletic man in the jersey kicked the ball over the fence.

b. Because he wanted to score a goal, the man kicked the ball.

  • どちらの文も"the man kicked the ball"が主節であるが、
    • aの文は主語である"man"が形容詞、前置詞句で修飾され、さらに"over the fence"で動詞が修飾され、語数が増えている。
    • bの文は副詞節を加えたことで語数が増えている。
  • つまり、句が加えられたのか節が加えられたのかという大きな違いがある。
  • 単語の数や1文あたりの平均語数という特徴量ではこの違いを捉えることはできない。

4.2.1 節の抽出¶

  • 依存文法に基づいて節を抽出します。
  • ここでは以下を節とします。
    1. advervial clause modifier (advcl): becaseu, whenなどの従位接続詞に導かれる副詞節
    2. relative clause modifier (relcl): which, whoなどの関係代名詞に導かれる関係代名詞節
    3. clausal complement (ccomp): thatで導かれる、主語や目的語になる節
    4. clausal subject (csubj): ccompが主語の位置に来たもの
In [1]:
import spacy
from spacy import displacy
nlp = spacy.load("en_core_web_sm")
In [2]:
# advclの例
doc = nlp("You can put the package wherever you like.")
displacy.render(doc)
You PRON can AUX put VERB the DET package NOUN wherever SCONJ you PRON like. VERB nsubj aux det dobj advmod nsubj advcl
In [3]:
# relclの例 
doc = nlp("My teacher, who came here in 1986, likes bananas.")
displacy.render(doc)
My PRON teacher, NOUN who PRON came VERB here ADV in ADP 1986, NUM likes VERB bananas. NOUN poss nsubj nsubj relcl advmod prep pobj dobj
In [4]:
# ccompの例
doc = nlp("I know that he stole the chicken.")
displacy.render(doc)
I PRON know VERB that SCONJ he PRON stole VERB the DET chicken. NOUN nsubj mark nsubj ccomp det dobj
In [5]:
# csubjの例
doc = nlp("What she said is interesting.")
displacy.render(doc)
What PRON she PRON said VERB is AUX interesting. ADJ dobj nsubj csubj acomp
In [6]:
# aclの例
doc = nlp("The girl dancing over there is my sister.")
displacy.render(doc)
The DET girl NOUN dancing VERB over ADP there PRON is AUX my PRON sister. NOUN det nsubj acl prep advmod poss attr
In [7]:
# これらの節の数をカウントする
text = "You can put the package wherever you like. My teacher, who came here in 1986, likes bananas. I know that he stole the chicken. She asked George to respond her. What she said is interesting. The girl dancing over there is my sister."

CLAUSE = ["advcl","relcl","ccomp","csubj"]

n = 0

doc = nlp(text)

for sent in doc.sents:
    for token in sent:
        if token.dep_ in CLAUSE:
            n += 1

n
Out[7]:
4

4.2.2 名詞句の抽出¶

  • 以下の2つの文は同じアイディアを同じ語数で表現していますが、文の構造は大きく異なります。

c. Since he drove the bus over-rapidly downhill, the brakes failed.

d. His over-rapid downhill driving of the bus caused brake failure.

  • cは2つの節で構成されているが、dはひとつ。

  • cの節の主語はそれぞれ1語、2語と短いが、dの主語は7語。

  • 一般に名詞句に含まれる単語の数(名詞句の長さ)は書き言葉の傾向である。

  • 話し言葉から書き言葉へと第二言語の能力が発達していくと仮定すると、名詞句の長さは発達の指標と考えることができる。

  • 以下の名詞句の語数をカウントする。

    1. noun subject (nsubj): 名詞句の主語
    2. direct object (dobj): 名詞句の直接目的語
    3. object of preposition (pobj): 前置詞句内の名詞句
In [8]:
# 名詞句の例
doc = nlp("A tall man put his blue hat on an old table.")
displacy.render(doc)
A DET tall ADJ man NOUN put VERB his PRON blue ADJ hat NOUN on ADP an DET old ADJ table. NOUN det amod nsubj poss amod dobj prep det amod pobj
In [9]:
# 名詞句のカウント

NOUNPHRASE = ["nsubj","dobj","pobj"]

doc = nlp("A tall man put his blue hat on an old table.")

n = 0
for token in doc:
    if token.dep_ in NOUNPHRASE:
        n += 1
        
n
Out[9]:
3
In [10]:
N = []

for chunk in doc.noun_chunks:
    N.append(len(chunk.text.split()))
    
N
Out[10]:
[3, 3, 3]

4.3 依存関係に関する特徴量を用いた自動採点¶

In [11]:
import os
# データの取得
fname_NS = os.listdir("../DATA02/NICE_NS/")

T_NS = []

for i in fname_NS:
    f = open("../DATA02/NICE_NS/"+i,"r")
    text = f.read()
    f.close()
    T_NS.append(text)
    
fname_NNS = os.listdir("../DATA02/NICE_NNS/")

T_NNS = []

for i in fname_NNS:
    f = open("../DATA02/NICE_NNS/"+i,"r")
    text = f.read()
    f.close()
    T_NNS.append(text)
In [12]:
# 正解ラベルの作成
Y = [0] * len(T_NNS) + [1] * len(T_NS)
In [13]:
# 1文あたりの節(対象となっている)の出現頻度
from nltk import sent_tokenize

CLAUSE = ["advcl","relcl","ccomp","xcomp","acl","csubj"]

CpS_NNS = []

for i in T_NNS:
    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_NNS.append(c/s)
    
CpS_NS = []

for i in T_NS:
    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_NS.append(c/s)
In [14]:
NL_NNS = []

for i in T_NNS:
    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_NNS.append(sum(tmp)/len(tmp))
        
NL_NS = []

for i in T_NS:
    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_NS.append(sum(tmp)/len(tmp))
In [15]:
X_NNS = []

X_NS = []

for i,j in zip(CpS_NNS,NL_NNS):
    X_NNS.append([i,j])
    
for i,j in zip(CpS_NS,NL_NS):
    X_NS.append([i,j])
In [16]:
X = X_NNS + X_NS
In [17]:
# パッケージのimport
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

import matplotlib.pyplot as plt
%matplotlib inline

N = []
S = []
X_train,X_test,y_train,y_test = train_test_split(X,Y,test_size=0.2)
for i in range(1,31):
    
    knn = KNeighborsClassifier(n_neighbors=i)
    knn.fit(X_train,y_train)
    score = knn.score(X_test,y_test)
    N.append(i)
    S.append(score)

plt.xlabel("number_of_k")
plt.ylabel("accuracy")
plt.plot(N,S)
Out[17]:
[<matplotlib.lines.Line2D at 0x3024368e0>]
No description has been provided for this image

練習問題¶

ここまで扱ってきたデータの英語学習者に関して部分的に評価値が付与されています。評価値は"../DATA02/nice_evaluation.csv"に保存されています。評価された作文は"../DATA02/NICE_NNS2"に保存されています。ここで学んだ同様の手順でこのデータを自動採点するシステムを構築し、交差検証を行いなさい。