第6回の演習問題の解答例¶

  • ../DATA01/text_train/には学習者の作文が保存されています。
  • これらの作文に対する評価は../DATA02/eva_train.csvに保存されています。
  • 評価はGood=1、Poor=0のように2値で付与されています。
  • このデータを用いて自動採点システムを構築し、../DATA01/text_test/に保存されている作文を評価します。
  • 評価に関して以下のような予想をし、これを前提に自動採点システムを構築します。
    • 評価が高い作文には複雑な文が含まれている→文の平均語数が多い
    • 評価が高い作文には難しい(頻度が低い)単語が含まれている→単語の平均文字数が多い
    • 評価が高い作文にはさまざまな単語が含まれている→TTRの値が大きい
  • また、特徴量の値が近いと同じ評価を受けると考えます。
In [1]:
import os
from nltk import word_tokenize,sent_tokenize
import pandas as pd
import numpy as np
In [2]:
# ファイルの読み込み
F_train = os.listdir("../DATA01/text_train/")

T_train = []

for i in F_train:
    f = open("../DATA01/text_train/"+i,"r")
    text = f.read()
    f.close()
    T_train.append(text)
In [3]:
WPS_train = []

for i in T_train:
    s = len(sent_tokenize(i))
    w = len(word_tokenize(i))
    wps = w/s
    WPS_train.append(wps)
In [4]:
LPW_train = []

for i in T_train:
    w = len(word_tokenize(i))
    l = len("".join(word_tokenize(i)))
    lpw = l/w
    LPW_train.append(lpw)
In [5]:
TTR_train = []

for i in T_train:
    i = i.lower()
    w = word_tokenize(i)
    ttr = len(set(w))/len(w)
    TTR_train.append(ttr)
In [6]:
data_train = pd.DataFrame({"WPS":WPS_train,"LPW":LPW_train,"TTR":TTR_train},index=F_train)
In [9]:
data_train.head()
Out[9]:
WPS LPW TTR
JPN004.txt 16.000000 4.500000 0.336806
JPN022.txt 14.380952 4.016556 0.347682
JPN156.txt 18.866667 4.708481 0.369258
JPN139.txt 17.105263 4.695385 0.403077
JPN038.txt 11.875000 4.091228 0.428070
In [11]:
data_train_norm = pd.DataFrame(index=F_train)

WPS_min = data_train.min()["WPS"]
WPS_max = data_train.max()["WPS"]
LPW_min = data_train.min()["LPW"]
LPW_max = data_train.max()["LPW"]


data_train_norm["WPS_nmd"] = (data_train["WPS"] - WPS_min) / (WPS_max - WPS_min)
data_train_norm["LPW_nmd"] = (data_train["LPW"] - LPW_min) / (LPW_max - LPW_min)
data_train_norm["TTR"] = data_train["TTR"]
In [12]:
eva_train = pd.read_csv("../DATA02/eva_train.csv",index_col=0)
data_train_norm["evaluation"] = eva_train["evaluation"]
In [15]:
# ファイルの読み込み
F_test = os.listdir("../DATA01/text_test/")

T_test = []

for i in F_test:
    f = open("../DATA01/text_test/"+i,"r")
    text = f.read()
    f.close()
    T_test.append(text)

WPS_test = []

for i in T_test:
    s = len(sent_tokenize(i))
    w = len(word_tokenize(i))
    wps = w/s
    WPS_test.append(wps)

LPW_test = []

for i in T_test:
    w = len(word_tokenize(i))
    l = len("".join(word_tokenize(i)))
    lpw = l/w
    LPW_test.append(lpw)

TTR_test = []

for i in T_test:
    i = i.lower()
    w = word_tokenize(i)
    ttr = len(set(w))/len(w)
    TTR_test.append(ttr)

data_test = pd.DataFrame({"WPS":WPS_test,"LPW":LPW_test,"TTR":TTR_test},index=F_test)

data_test_norm = pd.DataFrame(index=F_test)

WPS_min = data_test.min()["WPS"]
WPS_max = data_test.max()["WPS"]
LPW_min = data_test.min()["LPW"]
LPW_max = data_test.max()["LPW"]


data_test_norm["WPS_nmd"] = (data_test["WPS"] - WPS_min) / (WPS_max - WPS_min)
data_test_norm["LPW_nmd"] = (data_test["LPW"] - LPW_min) / (LPW_max - LPW_min)
data_test_norm["TTR"] = data_test["TTR"]
  • ↑のセルまでは授業中に説明したのでここでは割愛します。
  • 以下のコードを説明しないのはあまりに不親切だと思いましたので、行間に説明を挿入します。
In [16]:
# テストデータと訓練データの行名(JPN095.txtなど)を取得します。
N_test = data_test_norm.index
N_train = data_train_norm.index


# 処理した値を保存するリスト
L = []

# テストデータの行名をiに代入して個々に処理
for i in N_test:
    # data_test_normの各行の特徴量をtest_dataに代入
    test_data = data_test_norm.loc[i]
    # 入れ子のfor文の処理を一時的に保存するリスト
    tmp = []
    # 訓練データの行名をjに代入して個々に処理
    for j in N_train:
        #data_train_normの各行の特徴量をtrain_dataに代入
        train_data = data_train_norm.loc[j][:3]
        # i(テストデータ)とj(訓練データ)とのユークリッド距離を計算
        tmp.append(np.linalg.norm(test_data.values - train_data.values))
    # ひとつのi(テストデータ)に対してすべてのj(訓練データ)との距離を計算し終えたら結果をLに保存
    L.append(tmp)
In [17]:
# ユークリッド距離を比較するためのDataFrame
# 行(index)が訓練データ、列(column)がテストデータ)
# JPN137.txt行、JPN095.txt列はJPN137.txtとJPN095.txtのユークリッド距離
data_compare = pd.DataFrame(index=F_train)

for i,j in zip(F_test,L):
    data_compare[i] = j

# evaluationを追加
data_compare["evaluation"] = data_train_norm["evaluation"]
In [18]:
data_compare.head()
Out[18]:
JPN126.txt JPN086.txt JPN082.txt JPN095.txt JPN090.txt JPN117.txt JPN120.txt JPN093.txt JPN122.txt JPN092.txt evaluation
JPN004.txt 0.104245 0.529285 0.715177 0.714547 0.297400 0.310720 0.141384 0.236753 0.529120 0.523643 0
JPN022.txt 0.417132 0.110949 0.841232 0.298620 0.461649 0.381938 0.344222 0.381299 0.880573 0.417313 0
JPN156.txt 0.244790 0.732954 0.641025 0.925923 0.321325 0.513656 0.293913 0.413192 0.319478 0.615622 1
JPN139.txt 0.243041 0.703914 0.715036 0.891695 0.357685 0.445551 0.270289 0.337659 0.399427 0.642780 1
JPN038.txt 0.443775 0.223006 0.939885 0.353734 0.527739 0.291399 0.354451 0.284826 0.904746 0.551155 0
In [19]:
# 自動採点システム
# F_testにはテストデータのファイル名が入っています。
# テストデータのファイル名の列を昇順でソートします。
# そのテストデータに距離が近い上位7つの訓練データの"evaluation"の合計が3より大きい、つまり、
# そのテストデータに近いところにある訓練データについている評価の半分以上が1のとき、テストデータの
# 評価は1、それ以外は0という仕組み。

F_test.sort()
E = []

for i in F_test:
    e = sum(data_compare.sort_values(by=i).head(7)["evaluation"].values)
    if e > 3:
        f = 1
    else:
        f = 0
    E.append(f)
In [20]:
# 自動採点の結果
E
Out[20]:
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
In [21]:
# これらのテストデータには本当は評価が付与されてました。

eva_test = pd.read_csv("../DATA02/eva_test.csv",index_col=0)
eva_test
Out[21]:
evaluation
JPN082.txt 1
JPN086.txt 0
JPN090.txt 1
JPN092.txt 0
JPN093.txt 0
JPN095.txt 0
JPN117.txt 0
JPN120.txt 0
JPN122.txt 1
JPN126.txt 0