Rの自然言語処理

統計とは関係なさそうに見える関数
R
公開

2024年2月23日

Rに最初から入っているbaseパッケージには様々な関数があり、中には自然言語処理のような面白い動作をするものもあります。自然言語処理と言っても最近話題のAIのような高度なものではまったくありませんが、普通のプログラミング言語には見られない独特な関数です。次のようなものがあります。

abbreviate

abbreviate()関数は与えた文字列の省略形を作って返してくれます。例えば”abbreviate”を”abbr”のように短くします。これだけ聞くと「えっ?どうやってるの?」と思いますよね。実際に試してみましょう。irisデータのSpecies列のラベルについて省略形を作ってみましょう。

levels(iris$Species) |> abbreviate()
    setosa versicolor  virginica 
    "sets"     "vrsc"     "vrgn" 

結果は名前付きのベクトルで返ってきています。上の名前が元の文字列で、値が省略された文字列です。確かに短くなっています。デフォルトでは4文字に縮めるのですが、異なる長さを指定することもできます。

levels(iris$Species) |> abbreviate(minlength=3)
    setosa versicolor  virginica 
     "sts"      "vrs"      "vrg" 
levels(iris$Species) |> abbreviate(minlength=5)
    setosa versicolor  virginica 
   "setos"    "vrscl"    "vrgnc" 

省略形の作り方は、基本的には母音を削って子音を残すようなやり方になっているそうです。ということで残念ながらこれは日本語では使えないのですが、こんな関数があるというのは面白いですね。これはグラフの軸に名前を表示したいが長くて入りきらないようなときに使うことを想定しているのだと思います。

make.unique

次は文字列ベクトルの中に重複が含まれないように加工してくれるmake.unique()関数です。試しに”A”を3つ入力してみると次のようになります。

rep("A", 3) |> make.unique()
[1] "A"   "A.1" "A.2"

重複したものに”.1”、“.2”と連番が振られて重複が回避されています。この動きを見たことのある方もいらっしゃると思います。read.csv()関数でCSVデータを読み込むとき、1行目が列名になりますがこのように”.1”や”.2”が勝手に付いていたことはないでしょうか?それは同じ名前が重複していた場合です。read.csv()関数にはこれと同じように列名の重複を回避する機能が備わっています。

ところがdata frameの行名(row.names)の方は名前に重複があっても直してくれずに、次のようにエラーになってしまいます。

x <- data.frame(C1=1:5, C2=6:10)
row.names(x) <- c("A", "B", "A", "A", "B")
Error in `.rowNamesDF<-`(x, value = value): duplicate 'row.names' are not allowed

このようなエラーが出たときにとりあえず手っ取り早く先に進めたい場合、make.unique()関数が役に立つかも知れません。

row.names(x) <- make.unique(c("A", "B", "A", "A", "B"))
x
    C1 C2
A    1  6
B    2  7
A.1  3  8
A.2  4  9
B.1  5 10

もっともtidyverseではrow.namesは非推奨(行名も本来は1つの列であるはずという思想)で、tibbleではすでにrow.namesをセットできなくなっていますからこんなことをする機会もあまりなさそうですけどね。

make.names

Rの変数の名前に使える文字に制約があることはご存知のことと思いますが、その制約に引っ掛からない、変数名として有効な文字列に加工してくれるのがmake.names()関数です。例えば次のような形に直してくれます。

make.names(c("ABC-1 DEF/2", "2024/02/24", "if"))
[1] "ABC.1.DEF.2" "X2024.02.24" "if."        

これもread.csv()関数で列名を読み込んだときに見たことがあるかも知れませんが、変数として使えない文字はピリオドに置き換えられたり、数字で始まる名前は付けられないので”X”が前に付いたり、予約語そのものは回避されたりして元とは異なる列名になることがあります。data frameの列は$に続けて変数のように指定できるのでこの制約が必要なのでしょう。実はreadrread_csv()関数や、data.tablefread()関数ではこのような変換は行われず、変数として使えない文字列であってもそのままtibbledata.tableの列名になります。一見、柔軟性があるように見えますが、制約を満たさない列名を直接扱いたくなったときにいちいちエスケープして指定することになるので面倒です。Rに読み込んだらRで扱いやすいデータに加工しておくことが大事ですね。

さて、3つの関数を紹介しましたがまさに自然言語処理(?)を行う関数と言えるのではないでしょうか。せっかく用意されているのですからチャンスがあれば使っていきたいですね。