2015年2月19日木曜日

Rのduplicated関数を使ってデータフレームの重複チェック(改)

duplicated関数の引数にデータフレームを指定すると、すべての項目(列)を組み合わせた上での重複チェックができますよ、という話を以前書きました↓

Rのデータフレームで複数項目を組み合わせた重複のチェック - Rプログラミングの小ネタ

また、上記の記事では、すべてではなく一部の項目のみを組み合わせ対象にしたい場合は、interaction関数を使って新たにチェック用の列を作ってはどう?、というやり方も紹介しました。

が、duplicated関数がすべての列を対象にする動きなら、対象にしたい列だけで構成された新たなデータフレームを生成して、duplicated関数に渡した方がシンプルではないか、ということに気づきました。

例えば↓こんなデータがあって、

> d
   名字 名前 年齢
1  伊東 二郎   52
2  佐藤 五郎   52
3  遠藤 太郎   53
4  後藤 太郎   53
5  近藤 五郎   28
6  遠藤 二郎   33
7  後藤 四郎   52
8  須藤 次郎   28
9  伊東 二郎   35
10 遠藤 太郎   23
11 遠藤 史郎   38
12 工藤 吾郎   53
13 須藤 太郎   22
14 武藤 二郎   28
15 工藤 吾郎   53
16 伊東 二郎   22
17 遠藤 四郎   33
18 後藤 史郎   38
19 加藤 一郎   28
20 加藤 二郎   22


名字と名前だけを対象として重複チェックをしたい場合は、

> sum(duplicated( data.frame(d$名字, d$名前) ))
[1] 4

とか、

> d[duplicated( data.frame(d$名字, d$名前) ), ]
   名字 名前 年齢
9  伊東 二郎   35
10 遠藤 太郎   23
15 工藤 吾郎   53
16 伊東 二郎   22


という感じですね。interaction関数を使うよりも、シンプルだと思います。

が、duplicated関数の仕様って、2つ目以降が現れたときにTRUEとなる、というものなんですよね。つまり、伊東二郎さんが3回現れる場合、1つ目はFALSE、2つ目はTRUE、3つ目はTRUEという結果になります。なので、sum関数で数えた場合の結果は「2」となるし。TRUEのものを表示させようとすると上記の例のように、1つ目の伊東二郎さんは表示されないことになってしまいます。

重複の有無だけを確認したい場合は上記でもよさそうですが、重複したものをすべて確認したいという場合は、interaction関数を使ってチェック用の列を作った方がいいかもしれません。↓こんな感じ。(分かりやすいように、いちいち表示させてます)

> # チェック用の「氏名」列を作る
> d$氏名 <- interaction(d$名字, d$名前, drop=T)
> d

   名字 名前 年齢      氏名
1  伊東 二郎   52 伊東.二郎
2  佐藤 五郎   52 佐藤.五郎
3  遠藤 太郎   53 遠藤.太郎
4  後藤 太郎   53 後藤.太郎
5  近藤 五郎   28 近藤.五郎
6  遠藤 二郎   33 遠藤.二郎
7  後藤 四郎   52 後藤.四郎
8  須藤 次郎   28 須藤.次郎
9  伊東 二郎   35 伊東.二郎
10 遠藤 太郎   23 遠藤.太郎
11 遠藤 史郎   38 遠藤.史郎
12 工藤 吾郎   53 工藤.吾郎
13 須藤 太郎   22 須藤.太郎
14 武藤 二郎   28 武藤.二郎
15 工藤 吾郎   53 工藤.吾郎
16 伊東 二郎   22 伊東.二郎
17 遠藤 四郎   33 遠藤.四郎
18 後藤 史郎   38 後藤.史郎
19 加藤 一郎   28 加藤.一郎
20 加藤 二郎   22 加藤.二郎


> # 重複している行を抽出
> dup <- d[duplicated(d$氏名), ]
> dup

   名字 名前 年齢      氏名
9  伊東 二郎   35 伊東.二郎
10 遠藤 太郎   23 遠藤.太郎
15 工藤 吾郎   53 工藤.吾郎
16 伊東 二郎   22 伊東.二郎


> # 2回以上登場(=元のデータに3回以上登場)への対策
> dup_u <- unique(dup$氏名)
> dup_u

[1] 伊東.二郎 遠藤.太郎 工藤.吾郎
16 Levels: 加藤.一郎 近藤.五郎 佐藤.五郎 工藤.吾郎 遠藤.史郎 後藤.史郎 ... 武藤.二郎


> # ダブりのあったものを一覧として表示
> for(i in 1:length(dup_u)){
+   print( d[which(d$氏名 == dup_u[i]), ] )
+   cat("---------------------------\n")
+ }

   名字 名前 年齢      氏名
1  伊東 二郎   52 伊東.二郎
9  伊東 二郎   35 伊東.二郎
16 伊東 二郎   22 伊東.二郎
---------------------------
   名字 名前 年齢      氏名
3  遠藤 太郎   53 遠藤.太郎
10 遠藤 太郎   23 遠藤.太郎
---------------------------
   名字 名前 年齢      氏名
12 工藤 吾郎   53 工藤.吾郎
15 工藤 吾郎   53 工藤.吾郎
---------------------------


これで、重複のあった対象の1つ目のものも確認できるようになりました。




0 件のコメント:

コメントを投稿