統計解析ソフトRのデータ解析では、データフレームの行(row)に重複した名前をつけることができません。
対処法はケースバイケースで、重複する名前を削除して1個(一行)だけ残す方法がよく紹介されますが、たまたま同じ名前の行を持つデータを使いたいこともありますね。
本日は削除はせず、重複した名前に、機械的に異なる名前を割り振って重複しないようにする方法を紹介します。
例えば、"Sato" "Sato" ⇒ "Sato" "Sato.1" のようにします。
Rで最初から使えるbaseパッケージの make.names()
を使います。
😀 行名やリストのnameによく使うと思いますが、この方法は文字列ベクトルに対する処理なので他の使い道もあるかもしれません。
やってみよう
見本データ "namae_number.csv" です
1列目に名前、2列目に何かの数値があります。
SatoやSuzukiが複数行ありますが、すべて別人のデータであるとします。日本人に多い苗字ですから被ることもありますね*1。
NAMAE,NUMBER Sato,12 Suzuki,4 Takahashi,5 Sato,13 Tanaka,16 Ito,8 Watanabe,9 Suzuki,14 Yamamoyo,12 Nakamura,15 Kobayashi,7 Suzuki,10 Kato,6
読み込み
Rに見本データを読み込みます
> data <- read.table("namae_number.csv", sep=",", header=TRUE) > head(data) NAMAE NUMBER 1 Sato 12 2 Suzuki 4 3 Takahashi 5 4 Sato 13 5 Tanaka 16 6 Ito 8
ここで、NAMAE
列を行名(rownames)に変換しようとすると、重複した 'row.names' は許されませんとエラーが発生します。
> rownames(data) <- data$NAMAE `.rowNamesDF<-`(x, value = value) でエラー: 重複した 'row.names' は許されません 追加情報: 警告メッセージ: non-unique values when setting 'row.names': ‘Sato’, ‘Suzuki’
新しいNamae Oshiete
あらためて NAMAE列にある文字列の重複を確認してみます
> namae <- data$NAMAE > namae [1] "Sato" "Suzuki" "Takahashi" "Sato" "Tanaka" "Ito" [7] "Watanabe" "Suzuki" "Yamamoyo" "Nakamura" "Kobayashi" "Suzuki" [13] "Kato" > table(namae) # 文字列を集計 namae Ito Kato Kobayashi Nakamura Sato Suzuki Takahashi Tanaka 1 1 1 1 2 3 1 1 Watanabe Yamamoyo 1 1
ここから、make.names()
を使って新しい名前を作成します。
オプションで unique=TRUE
をつけると、前述のように重複した文字列が 固有のものに変換されます。
> new_name <- make.names(namae, unique=TRUE) #変換! ## 変換後の確認 > new_name [1] "Sato" "Suzuki" "Takahashi" "Sato.1" "Tanaka" "Ito" [7] "Watanabe" "Suzuki.1" "Yamamoyo" "Nakamura" "Kobayashi" "Suzuki.2" [13] "Kato"
一人目のSatoさんは "Sato" のまま、二人目から "Sato.1" "Sato.2" になりました。
※ 最初の人は "Sato.0" と考えるとわかりやすいでしょうか。0 から数え始めるのは、ちょっとRらしくない挙動ですね
新しい名前を行名に変換しようとすると、今度は成功します。
> rownames(data) <- new_name > head(data) NAMAE NUMBER Sato Sato 12 Suzuki Suzuki 4 Takahashi Takahashi 5 Sato.1 Sato 13 Tanaka Tanaka 16 Ito Ito 8
これで解決です。
改名したことを覚えていれば、元のNAMAE 列は消してもいいでしょう。
make.names()の変換法則
今回は重複解消のために使いましたが、 make.names()
は 文字列を syntactically valid nameにするのが主な機能である関数です。
その変換法則は以下の通りです。
- システム的に正しい名前に変更される
- nameに使えない文字(+, -, / など)はドット.に変換
- 数字から始まる名前は "X<数字>"に変換
※元から "X<数字>" という文字列がある場合は注意して!
unique=TRUE
の場合さらに
- 重複する場合は名前の後に ".1" ".2" ... が付与される
syntactically valid nameとは、Rの変数名に用いることができるname と同様の法則だと筆者は理解しました。
詳細には help(make.names)
を実行してヘルプをご覧ください。