一所懸命に手抜きする

デスクワークばかりのスポーツ嫌いで50歳も過ぎ、いよいよ足腰に衰えを感じつつある昨今。

R言語のuniqueや!duplicated で重複のないデータを取り出す

 SQLの select distinct では指定した列をキーにして重複のないデータを取得できます。
重複する行を削除するSELECT DISTINCT - 一所懸命に手抜きする 重複行削除の際、重複判定に指定したキー列項目以外の列も取得するSQL - 一所懸命に手抜きする  ではR言語で同様のことをするにはどうすればよいのでしょう。

Sampleデータ作成

 当ブロクで使うサンプルデータを作成するコード保管庫|R|一所懸命に手抜きする[忍者] に掲載したサンプル作成コードを実行すると

buyList
##  入荷日付 商品番号  商品名 当社原価 相手原価
##1 20170102    12345   XA-55     3500     3500
##2 20170103   132977    RX98     2980     3280
##3 20170103   349401 NOK0655     2500     2500
##4 20170103   349401 NOK0655     2500     2500
##5 20170104   227291 NOK2355     3500    35000
##6 20170104   227291 NOK2355     3500    35000
##7 20170104   349401 NOK0655     2500     2500
##8 20170105  5288923  JJ2CAN     6000     6200
##9 20170105   132977    RX98     2780     2980

という架空の商品購買データができます。

重複のないデータを抽出したい

 ここから、重複なくデータを抽出するにはどうすればよいでしょう。

unique関数を使うやり方

キー列が一つの場合
  unique(buyList$商品番号)
##[1] "12345"   "132977"  "349401"  "227291"  "5288923"

 SQL の SELECT DISTINCT と似たような結果です。
 unique 関数は指定されたキー項目で重複判定し、重複を除いたキーだけを返します。キーは一つしか指定できません
 この例ですと商品番号だけです。それだと何の商品かわからないので商品名もほしいのですが、このやり方ではできません。

キー列が複数の場合
  df<-subset(buyList,,c(商品番号,商品名))
  unique(df)
##  商品番号  商品名
##1    12345   XA-55
##2   132977    RX98
##3   349401 NOK0655
##5   227291 NOK2355
##8  5288923  JJ2CAN

 uniqueは引数を一つしかわたせないのですが列ではなくデータフレームを引数として渡せば、複数列で重複判定してくれます。
 商品番号と 商品名 だけがほしいのですから、その二つだけでsubsetデータフレームを作り、unique()の引数としています。

duplicated関数を使うやり方

 uniqueとは逆に重複を判定する関数としてduplicatedがあります。
 こちらの方が便利なところがあります。
 uniqueでは重複判定に用いたキー項目列しか抽出できませんが、!duplicatedを使うやり方だと抽出する項目を選べます。

duplicated関数は重複(TRUE)かFALSEかを返す

 重複でないということは !duplicated と表せますので、

!duplicated(buyList$商品番号,)
##[1]  TRUE  TRUE  TRUE FALSE  TRUE FALSE FALSE  TRUE FALSE

 unique はユニークデータを直接返しましたが、duplicatedや!duplicatedは重複しているかどうかをTRUE/FALSEで返します。

データフレーム[!duplicated(重複判定列),]

 ですから、!duplicated(重複していない)=TRUEだけを抜き出せば重複しないデータとなります。

buyList[!duplicated(buyList$商品番号),]
##  入荷日付 商品番号  商品名 当社原価 相手原価
##1 20170102    12345   XA-55     3500     3500
##2 20170103   132977    RX98     2980     3280
##3 20170103   349401 NOK0655     2500     2500
##5 20170104   227291 NOK2355     3500    35000
##8 20170105  5288923  JJ2CAN     6000     6200

 このやり方だと、商品番号という一つの項目で重複判定していますが、結果としては全列を返しています。

データフレーム[!duplicated(重複判定列),c(・・・)]

 もしも、仕入が発生した商品一覧がほしいというならば、商品番号と商品名だけで良いでしょうから

buyList[!duplicated(buyList$商品番号),c("商品番号","商品名")]
##  商品番号  商品名
##1    12345   XA-55
##2   132977    RX98
##3   349401 NOK0655
##5   227291 NOK2355
##8  5288923  JJ2CAN

 のように返す列をc()で指定してやることもできます。

データフレーム[!duplicated(重複判定データフレーム),c(・・・)]
  df<-subset(buyList,,c(商品番号,商品名))
buyList[!duplicated(df),]
##  入荷日付 商品番号  商品名 当社原価 相手原価
##1 20170102    12345   XA-55     3500     3500
##2 20170103   132977    RX98     2980     3280
##3 20170103   349401 NOK0655     2500     2500
##5 20170104   227291 NOK2355     3500    35000
##7 20170104   349401 NOK0655     2500     2500
##8 20170105  5288923  JJ2CAN     6000     6200
##9 20170105   132977    RX98     2780     2980

 複数列で重複判定するために、データフレームdfを作っています。dfと元のbuyListは列は違いますが行の内容は同じです。
 dfで重複行となっている行はbuyListでも重複しているのですから、dfで重複判定してbuyListから判定結果を返しています。

In SQL,SELECT DISTINCT returns only distinct columns.
In R languages,similar function unique also returns only distinct columns.
!duplicated can extract unique/distinct rows with full columns.