1 連語と単語の関係

I went to school yesterday.

I went
  went to
       to school
          school yesterday

2 2単語の連続

2.1 NICER JPN501の「単」語リスト

  • 前から順番に単語を並べる
setwd("NICER_NNS")

    yomikomi <- readLines("JPN501.txt", warn=F)    # 一行ずつ読み込む

    tmp <- grep("\\*(JPN|NS)", yomikomi, value=T)  # 発話部分の検索
    tmp1 <- gsub("\\*(JPN|NS)...:\t", "", tmp)     # 話者記号の削除
    tmp2 <- gsub("[[:punct:]]", "", tmp1)          # 句読点の削除
    tmp3 <- tolower(tmp2)                          # すべて小文字に
    tmp4 <- strsplit(tmp3, " ")                    # 半角スペースで、文字列を「切る」
    tmp5 <- unlist(tmp4)                           # リスト形式解除
    tmp5 <- tmp5[tmp5 != ""]                       # 空の要素を除く

head(tmp5, 20)
##  [1] "what"     "kind"     "of"       "sports"   "do"       "you"     
##  [7] "like"     "do"       "you"      "like"     "soccer"   "base"    
## [13] "ball"     "or"       "swimming" "there"    "are"      "many"    
## [19] "and"      "variety"
str(tmp5)
##  chr [1:319] "what" "kind" "of" "sports" "do" "you" "like" "do" "you" ...
  • 319個の単語

2.2 NICER JPN501の「連」語リスト

  • 並べた単語の n番目の単語と、n+1番目の単語をつないで(paste)、一つの単位(2単語の連語)にする
  • 2単語の連語リストを作成する
setwd("NICER_NNS")

  ngram <- NULL                                       # 最後に連語を入れる入れ物用意

    yomikomi <- readLines("JPN501.txt", warn=F)  

    tmp <- grep("\\*(JPN|NS)", yomikomi, value=T) 
    tmp1 <- gsub("\\*(JPN|NS)...:\t", "", tmp)   
    tmp2 <- gsub("[[:punct:]]", "", tmp1)
    tmp3 <- tolower(tmp2)
    tmp4 <- strsplit(tmp3, " ")
    tmp5 <- unlist(tmp4)
    tmp5 <- tmp5[tmp5 != ""]

  for (n in 1:(length(tmp5)-1)){                      # すべての単語数マイナス1回繰り返す
    
    bigram <- paste(tmp5[n], tmp5[n+1])               # n番目とn+1番目をくっつけてbigramに
    
    ngram <- c(ngram, bigram)                         # bigramを足して連語のリストをつくる
    
  }

head(ngram, 20)
##  [1] "what kind"      "kind of"        "of sports"      "sports do"     
##  [5] "do you"         "you like"       "like do"        "do you"        
##  [9] "you like"       "like soccer"    "soccer base"    "base ball"     
## [13] "ball or"        "or swimming"    "swimming there" "there are"     
## [17] "are many"       "many and"       "and variety"    "variety sports"
str(ngram)
##  chr [1:318] "what kind" "kind of" "of sports" "sports do" "do you" ...
  • 318個の連語

2.3 フォルダー内のすべてのファイルの2連語リストを作るプログラム: my2gram()

my2gram <- function(){                                  # 独自プログラムとして
  
  files <- list.files()                                 # フォルダー内のすべてのファイルの一覧

# ngram <- NULL                                         # ★間違い:ファイル内のすべての連語を入れる
  ngram.all <- NULL                                     # すべてのファイルのngramを入れる
  
  for (f in files){                                     # すべてのファイルに対して
    
    ngram <- NULL                                       # ★訂正後:ファイル内のすべての連語を入れる

    yomikomi <- readLines(f, warn=F)  

    tmp <- grep("\\*(JPN|NS)", yomikomi, value=T) 
    tmp1 <- gsub("\\*(JPN|NS)...:\t", "", tmp)   
    tmp2 <- gsub("[[:punct:]]", "", tmp1)
    tmp3 <- tolower(tmp2)
    tmp4 <- strsplit(tmp3, " ")
    tmp5 <- unlist(tmp4)
    tmp5 <- tmp5[tmp5 != ""]
    
     for (n in 1:(length(tmp5)-1)){                    # 各ファイルごとに
       bigram <- paste(tmp5[n], tmp5[n+1])
    
       ngram <- c(ngram, bigram)                       # 各ファイルごとの連語リスト
    
     }
    
    ngram.all <- c(ngram.all, ngram)                 # 各ファイルごとの連語リストを合わせていく
  
  }
  
    return(ngram.all)
}

2.3.1 my2gram()の実行

  • 30秒くらいかかります。
setwd("NICER_NNS")

nns.bigram <- my2gram()           # 実行した結果を nns.bigram に入れる
head(nns.bigram)
## [1] "what kind" "kind of"   "of sports" "sports do" "do you"    "you like"
length(nns.bigram)
## [1] 104551
  • 104,551個の連語

2.4 直接データフレームに入れる: my2gram.df()

my2gram.df <- function(){                                  # 独自プログラムとして
  
  files <- list.files()                                 # フォルダー内のすべてのファイルの一覧

# ngram <- NULL                                         # ★間違い:ファイル内のすべての連語を入れる
  ngram.all <- NULL                                     # すべてのファイルのngramを入れる
  
  for (f in files){                                     # すべてのファイルに対して
    
    ngram <- NULL                                       # ★訂正後:ファイル内のすべての連語を入れる

    yomikomi <- readLines(f, warn=F)  

    tmp <- grep("\\*(JPN|NS)", yomikomi, value=T) 
    tmp1 <- gsub("\\*(JPN|NS)...:\t", "", tmp)   
    tmp2 <- gsub("[[:punct:]]", "", tmp1)
    tmp3 <- tolower(tmp2)
    tmp4 <- strsplit(tmp3, " ")
    tmp5 <- unlist(tmp4)
    tmp5 <- tmp5[tmp5 != ""]
    
     for (n in 1:(length(tmp5)-1)){                    # 各ファイルごとに
       bigram <- paste(tmp5[n], tmp5[n+1])
    
       ngram <- c(ngram, bigram)                       # 各ファイルごとの連語リスト
    
     }
    
    ngram.all <- c(ngram.all, ngram)                 # 各ファイルごとの連語リストを合わせていく
  
  }
  
    #return(ngram.all)
  
    data.frame(ngram.all)
}

2.4.1 my2gram.df()の実行

setwd("NICER_NNS")

nns.bigram.df <- my2gram.df()           # 実行した結果を nns.bigram.df に入れる
str(nns.bigram.df)
## 'data.frame':    104551 obs. of  1 variable:
##  $ ngram.all: chr  "what kind" "kind of" "of sports" "sports do" ...
  • データフレームに入っている。

2.5 my2gram.df()の簡潔版my2gram.df2()

  • my2gram.df():ファイルごとにngramにいれて、それをまた、ngram.allに入れていた
  • my2gram.df2():最初から、ngram.allに入れていく
my2gram.df2 <- function(){                                  # 独自プログラムとして
  
  files <- list.files()                                 # フォルダー内のすべてのファイルの一覧

# ngram <- NULL                                         # ★間違い:ファイル内のすべての連語を入れる
  ngram.all <- NULL                                     # すべてのファイルのngramを入れる
  
  for (f in files){                                     # すべてのファイルに対して
    
#    ngram <- NULL                                       # これをやめる★

    yomikomi <- readLines(f, warn=F)  

    tmp <- grep("\\*(JPN|NS)", yomikomi, value=T) 
    tmp1 <- gsub("\\*(JPN|NS)...:\t", "", tmp)   
    tmp2 <- gsub("[[:punct:]]", "", tmp1)
    tmp3 <- tolower(tmp2)
    tmp4 <- strsplit(tmp3, " ")
    tmp5 <- unlist(tmp4)
    tmp5 <- tmp5[tmp5 != ""]
    
     for (n in 1:(length(tmp5)-1)){                    # 各ファイルごとに
       bigram <- paste(tmp5[n], tmp5[n+1])
    
#       ngram <- c(ngram, bigram)                       # これをやめて、
    
       ngram.all <- c(ngram.all, bigram)                # こちらに変更★
     }
    
#    ngram.all <- c(ngram.all, ngram)                 # これもやめる
  
  }
  
    #return(ngram.all)
  
    data.frame(ngram.all)
}

2.5.1 my2gram.df2()の実行

setwd("NICER_NNS")

nns.bigram.df2 <- my2gram.df2()           # 実行した結果を nns.bigram.df に入れる
str(nns.bigram.df2)
## 'data.frame':    104551 obs. of  1 variable:
##  $ ngram.all: chr  "what kind" "kind of" "of sports" "sports do" ...
  • 同じ結果:104551個の連語
head(nns.bigram.df)
##   ngram.all
## 1 what kind
## 2   kind of
## 3 of sports
## 4 sports do
## 5    do you
## 6  you like

2.6 頻度一覧表:table()

library(dplyr)
## 
##  次のパッケージを付け加えます: 'dplyr'
##  以下のオブジェクトは 'package:stats' からマスクされています:
## 
##     filter, lag
##  以下のオブジェクトは 'package:base' からマスクされています:
## 
##     intersect, setdiff, setequal, union
table(nns.bigram.df) %>% head()
## ngram.all
##       0 years       05 euro        1 2019        1 euro 1 grandfather 
##             1             1             1             2             1 
##        1 hour 
##             1

2.7 頻度一覧表自体をデータフレームに変換: as.data.frame()

table(nns.bigram.df) %>% as.data.frame() %>% head()
##       ngram.all Freq
## 1       0 years    1
## 2       05 euro    1
## 3        1 2019    1
## 4        1 euro    2
## 5 1 grandfather    1
## 6        1 hour    1

2.8 頻度一覧表自体のデータフレーム

nns.bigram.df.table <- table(nns.bigram.df) %>% as.data.frame()

2.9 データフレーム内の並べ替え: dplyr::arrange()

  • arrange(データフレーム, 見出し)
library(dplyr)


arrange(nns.bigram.df.table, Freq)  %>%  head()
##       ngram.all Freq
## 1       0 years    1
## 2       05 euro    1
## 3        1 2019    1
## 4 1 grandfather    1
## 5        1 hour    1
## 6           1 i    1
  • 逆順オプション arrange(データフレーム, desc(見出し))
arrange(nns.bigram.df.table, desc(Freq))  %>%  head(20)
##      ngram.all Freq
## 1        it is  531
## 2      i think  467
## 3       in the  353
## 4  high school  287
## 5        a lot  280
## 6      want to  273
## 7        i was  271
## 8       lot of  263
## 9    there are  260
## 10     have to  242
## 11    in japan  228
## 12      when i  223
## 13 for example  216
## 14      of the  210
## 15  think that  206
## 16   the world  194
## 17      we can  186
## 18      i have  184
## 19        so i  183
## 20     you can  181

2.10 結果の可視化

2.10.1 データフレームに保存

nns.bi.freq <- arrange(nns.bigram.df.table, desc(Freq))

head(nns.bi.freq)
##     ngram.all Freq
## 1       it is  531
## 2     i think  467
## 3      in the  353
## 4 high school  287
## 5       a lot  280
## 6     want to  273

2.10.2 ランクを数字で追加

nns.bi.freq %>% mutate(Rank = row_number()) %>% head()
##     ngram.all Freq Rank
## 1       it is  531    1
## 2     i think  467    2
## 3      in the  353    3
## 4 high school  287    4
## 5       a lot  280    5
## 6     want to  273    6

2.10.3 mutateした結果を保存

nns.bi.freq.rank <- nns.bi.freq %>% mutate(Rank = row_number())

2.10.4 上位30位までだけ

library(ggplot2)

nns.bi.freq.rank.30 <- head(nns.bi.freq.rank, 30)

g <- ggplot(nns.bi.freq.rank.30)
g <- g + aes(x = Rank, y = Freq)
g <- g + geom_point()
plot(g)

2.10.4.1 ラベルを作っておく

koumoku <- as.vector(nns.bi.freq.rank.30$ngram.all)

koumoku
##  [1] "it is"          "i think"        "in the"         "high school"   
##  [5] "a lot"          "want to"        "i was"          "lot of"        
##  [9] "there are"      "have to"        "in japan"       "when i"        
## [13] "for example"    "of the"         "think that"     "the world"     
## [17] "we can"         "i have"         "so i"           "you can"       
## [21] "if you"         "to study"       "to be"          "and i"         
## [25] "is not"         "to play"        "to do"          "go to"         
## [29] "playing sports" "is very"

2.10.4.2 ラベルを付けたグラフ

nns.bi.freq.rank.30 <- head(nns.bi.freq.rank, 30)

g <- ggplot(nns.bi.freq.rank.30)
g <- g + aes(x = Rank, y = Freq)
g <- g + geom_point()

g <- g + geom_line()

g <- g + scale_x_continuous(breaks=seq(1:30), labels=koumoku)

plot(g)

2.10.4.3 縦横変換・順位表示調整(逆順)

nns.bi.freq.rank.30 <- head(nns.bi.freq.rank, 30)

g <- ggplot(nns.bi.freq.rank.30)
g <- g + aes(x = Rank, y = Freq)
g <- g + geom_point()

g <- g + geom_line()

#g <- g + scale_x_continuous(breaks=seq(1:30), labels=koumoku)

g <- g + scale_x_reverse(breaks=seq(1:30), labels=koumoku)

g <- g + coord_flip()

plot(g)

3 授業内課題

3.1 学習者と母語話者の三連語(trigram)表現の頻度比較

4 連語の「強さ」:MIスコア (Mutual Information)

https://sugiura-ken.org/wiki/wiki.cgi/exp?page=MI

4.1 共起の「強さ」とは

  • 二つの単語が並んで使われる「強さ」
  • たまたま二つが並ぶ確率と、二つが並んだ確率を比べる
    • たまたまの確率と二つ並んだ確率が、ほぼ同じなら、「弱い」
    • たまたまの確率よりも、二つ並んだ確率の方が高い:「強い」

4.2 基本の式

\[ MI = log2((共起頻度×コーパス総語数)/(片方の頻度×もう片方の頻度)) \]

4.3 必要な数値

  1. 共起頻度
  2. コーパス総語数
  3. 片方の単語の頻度
  4. もう一方の単語の頻度

4.4 必要なデータ

4.4.1 連語頻度一覧表

4.4.2 単語リスト一覧表 my2gram.df()を修正して my1gram.df()

my1gram.df <- function(){                                  # 独自プログラムとして
  
  files <- list.files()                                 # フォルダー内のすべてのファイルの一覧

  word.all <- NULL                                    # すべてのファイルのwordを入れる
  
  for (f in files){                                     # すべてのファイルに対して

    yomikomi <- readLines(f, warn=F)  

    tmp <- grep("\\*(JPN|NS)", yomikomi, value=T) 
    tmp1 <- gsub("\\*(JPN|NS)...:\t", "", tmp)   
    tmp2 <- gsub("[[:punct:]]", "", tmp1)
    tmp3 <- tolower(tmp2)
    tmp4 <- strsplit(tmp3, " ")
    tmp5 <- unlist(tmp4)
    tmp5 <- tmp5[tmp5 != ""]

    word.all <- c(word.all, tmp5)                 # 単語リストを合わせていく
  
  }

    data.frame(word.all)
}

4.4.3 my1gram.df()の実行

setwd("NICER_NNS")
nns.1gram.df <- my1gram.df()

4.4.4 頻度一覧表自体をデータフレームに変換: as.data.frame()

nns.1gram.df.table <- table(nns.1gram.df) %>% as.data.frame()

4.4.5 並べ替え

arrange(nns.1gram.df.table, desc(Freq))  %>%  head(30)
##    word.all Freq
## 1        to 3634
## 2         i 3096
## 3       the 2994
## 4       and 2462
## 5        is 2427
## 6        in 2197
## 7        of 2011
## 8         a 1473
## 9    sports 1274
## 10       we 1266
## 11       it 1254
## 12      for 1215
## 13     that 1211
## 14      you 1194
## 15     have 1068
## 16     they 1026
## 17      are 1016
## 18   people  959
## 19    money  935
## 20       so  900
## 21      not  853
## 22      can  848
## 23    think  773
## 24   school  736
## 25      but  726
## 26       do  646
## 27       my  640
## 28  english  631
## 29     many  625
## 30 students  579

4.5 例 playing sports vs. doing sports

4.6 連語リスト

  1. 連語表現のリストから playing sportsの頻度を調べる
nns.bigram.df.table %>% filter(ngram.all == "playing sports")
##        ngram.all Freq
## 1 playing sports  155
  1. 学習者データの総語数
  • nns.1gram.df.tableのFreqの合計: sum()
sum(nns.1gram.df.table$Freq)
## [1] 104932
  1. 単語リストから playingの頻度を調べる
nns.1gram.df.table %>% filter(word.all == "playing")
##   word.all Freq
## 1  playing  330
  1. 単語リストから sportsの頻度を調べる
nns.1gram.df.table %>% filter(word.all == "sports")
##   word.all Freq
## 1   sports 1274

4.7 MIスコアの計算

4.7.1 “playing sports”

MI <- function(xy, x, y, N){
  
    log2(xy*N/(x*y))
}
MI(155, 330, 1274, 104932)
## [1] 5.273748

4.7.2 “doing sports”

nns.bigram.df.table %>% filter(ngram.all == "doing sports")
##      ngram.all Freq
## 1 doing sports   55
nns.1gram.df.table %>% filter(word.all == "doing")
##   word.all Freq
## 1    doing  108
MI(55, 108, 1274, 104932)
## [1] 5.390418

4.7.3 比較の結果

playing sportsは頻度は155で、MIスコアは5.3、doing sportsは頻度は55で、MIスコアは5.4であった。 学習者は、playing sportsを3倍ほど多く使うが、表現の結びつきの強さはそれほど違いはなかった。

5 課題