library(conflicted)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2
library(arrow)
library(stringi)
library(reticulate)

# ファイルの読み込み
aozora <- read_parquet("https://github.com/ghmagazine/awesomebook_v2/raw/main/data/aozora.parquet")

文字列操作はstringr、stringiパッケージの出番。これもtidyverseに含まれる。


13-1 部分文字列の検出・抽出・置換

Q: URLから芥川竜之介の作品を判定して抽出

Awesome

aozora |>
  dplyr::filter(str_detect(url, "/000879/"))
## # A tibble: 5 × 5
##   text_id title    text                                       url   published_at
##     <int> <chr>    <chr>                                      <chr> <chr>       
## 1      92 蜘蛛の糸 "\n[#8字下げ]一[#「一」は中見出し]… http… 1918年07月  
## 2     152 早春     "\n 大学生の中村《なかむら》は薄《うす》… http… 1925年01月  
## 3     127 羅生門   "\n ある日の暮方の事である。一人の下人《… http… 1915年11月  
## 4      42 鼻       "\n 禅智内供《ぜんちないぐ》の鼻と云えば… http… 1916年02月  
## 5   43015 杜子春   "\n[#5字下げ]一[#「一」は中見出し]… http… 1920年07月

Q: 出版年月から年と月を位置指定で抽出

抽出の開始位置を指定するやり方

Awesome

aozora |>
  mutate(
    year = str_sub(published_at, 1, 4),
    month = str_sub(published_at, 6, 7)
  ) |>
  select(text_id, title, published_at, year, month)
## # A tibble: 20 × 5
##    text_id title              published_at year  month
##      <int> <chr>              <chr>        <chr> <chr>
##  1      92 蜘蛛の糸           1918年07月   1918  "07" 
##  2     152 早春               1925年01月   1925  "01" 
##  3     473 よだかの星         1934年       1934  ""   
##  4   43754 注文の多い料理店   1924年12月   1924  "12" 
##  5     470 セロ弾きのゴーシュ 1934年       1934  ""   
##  6     456 銀河鉄道の夜       1934年       1934  ""   
##  7     462 風の又三郎         1934年       1934  ""   
##  8     789 吾輩は猫である     1905年01月   1905  "01" 
##  9     752 坊っちゃん         1906年04月   1906  "04" 
## 10   56143 それから           1909年06月   1909  "06" 
## 11     794 三四郎             1908年09月   1908  "09" 
## 12     773 こころ             1914年08月   1914  "08" 
## 13    1567 走れメロス         1940年05月   1940  "05" 
## 14     301 人間失格           1948年08月   1948  "08" 
## 15    1565 斜陽               1947年07月   1947  "07" 
## 16     258 グッド・バイ       1948年07月   1948  "07" 
## 17    2253 ヴィヨンの妻       1947年03月   1947  "03" 
## 18     127 羅生門             1915年11月   1915  "11" 
## 19      42 鼻                 1916年02月   1916  "02" 
## 20   43015 杜子春             1920年07月   1920  "07"

Q: 出版年月のフォーマットをYYYY年MM月からYYYY-MMに変換(部分文字列の検出、置換)

部分文字列の検出と置換

Awesome

aozora |>
  mutate(
    published_at = if_else(
      str_detect(published_at, "月"),
      str_replace(str_replace(published_at, "年", "-"), "月", ""),
      str_replace(published_at, "年", "")
    )
  ) |>
  select(text_id, title, published_at)
## # A tibble: 20 × 3
##    text_id title              published_at
##      <int> <chr>              <chr>       
##  1      92 蜘蛛の糸           1918-07     
##  2     152 早春               1925-01     
##  3     473 よだかの星         1934        
##  4   43754 注文の多い料理店   1924-12     
##  5     470 セロ弾きのゴーシュ 1934        
##  6     456 銀河鉄道の夜       1934        
##  7     462 風の又三郎         1934        
##  8     789 吾輩は猫である     1905-01     
##  9     752 坊っちゃん         1906-04     
## 10   56143 それから           1909-06     
## 11     794 三四郎             1908-09     
## 12     773 こころ             1914-08     
## 13    1567 走れメロス         1940-05     
## 14     301 人間失格           1948-08     
## 15    1565 斜陽               1947-07     
## 16     258 グッド・バイ       1948-07     
## 17    2253 ヴィヨンの妻       1947-03     
## 18     127 羅生門             1915-11     
## 19      42 鼻                 1916-02     
## 20   43015 杜子春             1920-07

Q: URLから人物IDと作品IDを抽出 (正規表現による抽出)

Awesome

aozora |>
  mutate(
    author_id = str_match(url, "cards/0*([1-9][0-9]*)/")[,2],
    text_id = str_match(url, "card([0-9]+)\\.")[,2]
  ) |>
  select(title, url, author_id, text_id)
## # A tibble: 20 × 4
##    title              url                                      author_id text_id
##    <chr>              <chr>                                    <chr>     <chr>  
##  1 蜘蛛の糸           https://www.aozora.gr.jp/cards/000879/c… 879       92     
##  2 早春               https://www.aozora.gr.jp/cards/000879/c… 879       152    
##  3 よだかの星         https://www.aozora.gr.jp/cards/000081/c… 81        473    
##  4 注文の多い料理店   https://www.aozora.gr.jp/cards/000081/c… 81        43754  
##  5 セロ弾きのゴーシュ https://www.aozora.gr.jp/cards/000081/c… 81        470    
##  6 銀河鉄道の夜       https://www.aozora.gr.jp/cards/000081/c… 81        456    
##  7 風の又三郎         https://www.aozora.gr.jp/cards/000081/c… 81        462    
##  8 吾輩は猫である     https://www.aozora.gr.jp/cards/000148/c… 148       789    
##  9 坊っちゃん         https://www.aozora.gr.jp/cards/000148/c… 148       752    
## 10 それから           https://www.aozora.gr.jp/cards/000148/c… 148       56143  
## 11 三四郎             https://www.aozora.gr.jp/cards/000148/c… 148       794    
## 12 こころ             https://www.aozora.gr.jp/cards/000148/c… 148       773    
## 13 走れメロス         https://www.aozora.gr.jp/cards/000035/c… 35        1567   
## 14 人間失格           https://www.aozora.gr.jp/cards/000035/c… 35        301    
## 15 斜陽               https://www.aozora.gr.jp/cards/000035/c… 35        1565   
## 16 グッド・バイ       https://www.aozora.gr.jp/cards/000035/c… 35        258    
## 17 ヴィヨンの妻       https://www.aozora.gr.jp/cards/000035/c… 35        2253   
## 18 羅生門             https://www.aozora.gr.jp/cards/000879/c… 879       127    
## 19 鼻                 https://www.aozora.gr.jp/cards/000879/c… 879       42     
## 20 杜子春             https://www.aozora.gr.jp/cards/000879/c… 879       43015

13-2 区切り文字による文字列分割

Q: 句点で文に分割

Awesome

aozora |>
  mutate(sentence_list = str_split(text, "。")) |>
  select(text_id, title, sentence_list)
## # A tibble: 20 × 3
##    text_id title              sentence_list
##      <int> <chr>              <list>       
##  1      92 蜘蛛の糸           <chr [62]>   
##  2     152 早春               <chr [122]>  
##  3     473 よだかの星         <chr [208]>  
##  4   43754 注文の多い料理店   <chr [210]>  
##  5     470 セロ弾きのゴーシュ <chr [433]>  
##  6     456 銀河鉄道の夜       <chr [1,121]>
##  7     462 風の又三郎         <chr [1,069]>
##  8     789 吾輩は猫である     <chr [7,488]>
##  9     752 坊っちゃん         <chr [2,452]>
## 10   56143 それから           <chr [5,188]>
## 11     794 三四郎             <chr [5,904]>
## 12     773 こころ             <chr [4,655]>
## 13    1567 走れメロス         <chr [460]>  
## 14     301 人間失格           <chr [1,177]>
## 15    1565 斜陽               <chr [1,939]>
## 16     258 グッド・バイ       <chr [543]>  
## 17    2253 ヴィヨンの妻       <chr [286]>  
## 18     127 羅生門             <chr [153]>  
## 19      42 鼻                 <chr [160]>  
## 20   43015 杜子春             <chr [202]>

Q: 複数の区切り文字で文に分割

Awesome

test1 <- aozora |>
  mutate(sentence_list = str_split(text, "。|\\n")) |>
  select(text_id, title, sentence_list)

Q: 分割結果の配列を列に展開

Awesome

aozora |>
  mutate(
    sentence_list = str_split(text, fixed("。")),
    first_sentence = map_chr(sentence_list, ~ .[1]),
    second_sentence = map_chr(sentence_list, ~ .[2])
  ) |>
  select(text_id, title, first_sentence, second_sentence)
## # A tibble: 20 × 4
##    text_id title              first_sentence                     second_sentence
##      <int> <chr>              <chr>                              <chr>          
##  1      92 蜘蛛の糸           "\n[#8字下げ]一[#「一」は中… "御釈迦様《お… 
##  2     152 早春               "\n 大学生の中村《なかむら》は薄… "階段を登りつ… 
##  3     473 よだかの星         "\n よだかは、実にみにくい鳥です" "\n 顔は、と… 
##  4   43754 注文の多い料理店   "\n 二人の若い紳士《しんし》が、… "\n「ぜんたい… 
##  5     470 セロ弾きのゴーシュ "\n ゴーシュは町の活動写真館でセ… "けれどもあん… 
##  6     456 銀河鉄道の夜       "\n[#3字下げ]一、午后《ごご》… "」先生は、黒… 
##  7     462 風の又三郎         "\n[#ここから3字下げ]\nどっど… "\n 教室はた… 
##  8     789 吾輩は猫である     "\n[#8字下げ]一[#「一」は中… "名前はまだ無… 
##  9     752 坊っちゃん         "\n[#5字下げ]一[#「一」は中… "小学校に居る… 
## 10   56143 それから           "\n[#5字下げ]一[#「一」は中… "けれども、そ… 
## 11     794 三四郎             "\n[#7字下げ]一[#「一」は中… "このじいさん… 
## 12     773 こころ             "\n[#2字下げ]上 先生と私[#… "だからここで… 
## 13    1567 走れメロス         "\n メロスは激怒した"             "必ず、かの邪… 
## 14     301 人間失格           "\n[#3字下げ]はしがき[#「は… "\n 一葉は、… 
## 15    1565 斜陽               "\n[#5字下げ]一[#「一」は中… "\n「髪の毛?… 
## 16     258 グッド・バイ       "\n[#6字下げ]変心 (一)[#… "早春の雨であ… 
## 17    2253 ヴィヨンの妻       "\n[#5字下げ]一[#「一」は中… "\n 夫は、隣… 
## 18     127 羅生門             "\n ある日の暮方の事である"       "一人の下人《… 
## 19      42 鼻                 "\n 禅智内供《ぜんちないぐ》の鼻… "長さは五六寸… 
## 20   43015 杜子春             "\n[#5字下げ]一[#「一」は中… "\n 唐《とう…

Q: 分割結果の配列を行に展開

Awesome

aozora |>
  mutate(sentence = str_split(text, "。")) |>
  select(text_id, title, sentence) |>
  unnest(sentence)
## # A tibble: 33,832 × 3
##    text_id title    sentence                                                    
##      <int> <chr>    <chr>                                                       
##  1      92 蜘蛛の糸 "\n[#8字下げ]一[#「一」は中見出し]\n\n ある日の事で…
##  2      92 蜘蛛の糸 "御釈迦様《おしゃかさま》は極楽の蓮池《はすいけ》のふちを、…
##  3      92 蜘蛛の糸 "池の中に咲いている蓮《はす》の花は、みんな玉のようにまっ白…
##  4      92 蜘蛛の糸 "極楽は丁度朝なのでございましょう"                          
##  5      92 蜘蛛の糸 "\n やがて御釈迦様はその池のふちに御佇《おたたず》みになっ…
##  6      92 蜘蛛の糸 "この極楽の蓮池の下は、丁度|地獄《じごく》の底に当って居り…
##  7      92 蜘蛛の糸 "\n するとその地獄の底に、※[#「特のへん+廴+聿」、第3…  
##  8      92 蜘蛛の糸 "この※[#「特のへん+廴+聿」、第3水準1-87-71]陀多と云う… 
##  9      92 蜘蛛の糸 "と申しますのは、ある時この男が深い林の中を通りますと、小さ…
## 10      92 蜘蛛の糸 "そこで※[#「特のへん+廴+聿」、第3水準1-87-71]陀多は早… 
## # ℹ 33,822 more rows

13-3 文字列データのクレンジング

Q: ユニコード正規化

stringiパッケージのstri_trans_nfkc()関数を使います。

Awesome

aozora |>
  mutate(text = stri_trans_nfkc(text)) |>
  select(text_id, title, text)
## # A tibble: 20 × 3
##    text_id title              text                                              
##      <int> <chr>              <chr>                                             
##  1      92 蜘蛛の糸           "\n[#8字下げ]一[#「一」は中見出し]\n\n ある日の事…
##  2     152 早春               "\n 大学生の中村《なかむら》は薄《うす》い春のオ… 
##  3     473 よだかの星         "\n よだかは、実にみにくい鳥です。\n 顔は、ところ…
##  4   43754 注文の多い料理店   "\n 二人の若い紳士《しんし》が、すっかりイギリス… 
##  5     470 セロ弾きのゴーシュ "\n ゴーシュは町の活動写真館でセロを弾く係りでし… 
##  6     456 銀河鉄道の夜       "\n[#3字下げ]一、午后《ごご》の授業[#「一、午后の…
##  7     462 風の又三郎         "\n[#ここから3字下げ]\nどっどど どどうど どどうど…
##  8     789 吾輩は猫である     "\n[#8字下げ]一[#「一」は中見出し]\n\n 吾輩《わが…
##  9     752 坊っちゃん         "\n[#5字下げ]一[#「一」は中見出し]\n\n 親譲《おや…
## 10   56143 それから           "\n[#5字下げ]一[#「一」は中見出し]\n\n 誰か慌《あ…
## 11     794 三四郎             "\n[#7字下げ]一[#「一」は中見出し]\n\n うとうとと…
## 12     773 こころ             "\n[#2字下げ]上 先生と私[#「上 先生と私」は大見出…
## 13    1567 走れメロス         "\n メロスは激怒した。必ず、かの邪智暴虐《じゃち… 
## 14     301 人間失格           "\n[#3字下げ]はしがき[#「はしがき」は大見出し]\n\…
## 15    1565 斜陽               "\n[#5字下げ]一[#「一」は中見出し]\n\n 朝、食堂で…
## 16     258 グッド・バイ       "\n[#6字下げ]変心 (一)[#「変心 (一)」は中見出し]\…
## 17    2253 ヴィヨンの妻       "\n[#5字下げ]一[#「一」は中見出し]\n\n あわただし…
## 18     127 羅生門             "\n ある日の暮方の事である。一人の下人《げにん》… 
## 19      42 鼻                 "\n 禅智内供《ぜんちないぐ》の鼻と云えば、池《い… 
## 20   43015 杜子春             "\n[#5字下げ]一[#「一」は中見出し]\n\n 或《ある》…

Q: 不要な文字列パターンの除去(正規表現による除去)

Awesome

aozora |>
  # (1) "。" または "\n" で text を分割し、新しい列 sentence を追加
  mutate(sentence = str_split(text, "。|\n")) |>
  select(text_id, title, sentence) |>
  unnest(sentence) |>
  mutate(
    sentence = sentence |>
      # (2) ユニコード正規化
      stri_trans_nfkc() |>
      # (3) 正規表現による不要パターンの除去
      str_replace_all("《.*?》|\\[#.*?\\]|[\\|※「」()]", "") |> 
      # (4) 先頭や末尾のスペースの除去   
      str_trim()
    ) |>
  # (5) 長さが1文字以上の行のみ抽出
  dplyr::filter(nchar(sentence) >= 1)
## # A tibble: 39,774 × 3
##    text_id title    sentence                                                   
##      <int> <chr>    <chr>                                                      
##  1      92 蜘蛛の糸 一                                                         
##  2      92 蜘蛛の糸 ある日の事でございます                                     
##  3      92 蜘蛛の糸 御釈迦様は極楽の蓮池のふちを、独りでぶらぶら御歩きになって…
##  4      92 蜘蛛の糸 池の中に咲いている蓮の花は、みんな玉のようにまっ白で、その…
##  5      92 蜘蛛の糸 極楽は丁度朝なのでございましょう                           
##  6      92 蜘蛛の糸 やがて御釈迦様はその池のふちに御佇みになって、水の面を蔽っ…
##  7      92 蜘蛛の糸 この極楽の蓮池の下は、丁度地獄の底に当って居りますから、水…
##  8      92 蜘蛛の糸 するとその地獄の底に、陀多と云う男が一人、ほかの罪人と一し…
##  9      92 蜘蛛の糸 この陀多と云う男は、人を殺したり家に火をつけたり、いろいろ…
## 10      92 蜘蛛の糸 と申しますのは、ある時この男が深い林の中を通りますと、小さ…
## # ℹ 39,764 more rows

13-4 形態素解析による日本語文章の単語分解と単語抽出

形態素解析はR言語ではRMecabを使うのが一般的だが、テキストで『改訂新版前処理大全』で使われているspaCyとGiNZAとは挙動が異なるため、いったん省略します。

Q: 文を単語に分解(形態素解析)

Awesome

Q: 特定の品詞の抽出とストップワードの除去

Awesome


13-5 文章のベクトル化

Q: bag-of-wordsベクトルの作成

Awesome

Q: TF-IDF 特徴量の作成

Awesome

Q: 平均単語ベクトル特徴量の作成