Rデータフレームの特定の重複レコードを1つ以外すべて削除するにはどうすればよいですか?[閉まっている]


16

重複したIDを含むデータフレームがあります。重複したIDを持つレコードを削除し、最大値を持つ行のみを保持します。

そのため、このような構造の場合(他の変数は表示されません):

id var_1
1 2
1 4
2 1
2 3
3 5
4 2

これを生成したい:

id var_1
1 4
2 3
3 5
4 2

unique()とduplicated()については知っていますが、最大化ルールを組み込む方法がわかりません...


それは純粋にプログラミング関連のタスクであり、統計とはほとんど関係がないため、実際にはstackoverflowにあるはずです
愛好家

回答:


24

1つの方法は、データを逆ソートし、duplicatedすべての重複を削除するために使用することです。私にとって、この方法は、applyを使用する方法よりも概念的に簡単です。私もそれは非常に高速であるべきだと思います。

# Some data to start with:
z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
# id var
#  1   2
#  1   4
#  2   1
#  2   3
#  3   5
#  4   2

# Reverse sort
z <- z[order(z$id, z$var, decreasing=TRUE),]
# id var
#  4   2
#  3   5
#  2   3
#  2   1
#  1   4
#  1   2

# Keep only the first row for each duplicate of z$id; this row will have the
# largest value for z$var
z <- z[!duplicated(z$id),]

# Sort so it looks nice
z <- z[order(z$id, z$var),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2

編集:上記の逆の並べ替えは、並べ替えさえする必要がないことを実感しましたidz[order(z$var, decreasing=TRUE),]代わりに使用するだけで、同様に機能します。

もう1つ考えます... var列が数値の場合、id昇順であるvarが降順であるように並べ替える簡単な方法があります。これにより、最後に並べ替える必要がなくなります(並べ替えを希望する場合でも)。

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))

# Sort: id ascending, var descending
z <- z[order(z$id, -z$var),]

# Remove duplicates
z <- z[!duplicated(z$id),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2

1
このアプローチは、「split-compute-rbind」よりも大幅に高速です。さらに、複数の要因でグループ化できます。cの場合 650,000行(8、狭い、列)「順序重複」アプローチは55秒かかり、分割-計算-rbind ... 1時間15分でした。もちろん、集計計算が重複の選択またはフィルタリング以外の場合、後者のアプローチまたは同様のplyrベースのアプローチが必要です。
mjv 14

7

実際には、同じIDを持つ要素から最大の要素を選択する必要があります。そのためにはddply、パッケージplyrから使用できます。

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
> ddply(dt,.(id),summarise,var_1=max(var))
   id var_1
1  1   4
2  2   3
3  3   4
4  4   2

uniqueそしてduplicatedあなたのケースで、あなただけではない記録し、重複したIDを持って、重複レコードを除去するためのものです。

更新:追加の変数がある場合のコードは次のとおりです。

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2),bu=rnorm(6))
> ddply(dt,~id,function(d)d[which.max(d$var),])

他の変数があった場合:どうやってそれらを運びますか?
アニコ

私たちはそのような質問を動かしません。

6

base-Rソリューションにはsplit、次のようなが含まれます。

z<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
do.call(rbind,lapply(split(z,z$id),function(chunk) chunk[which.max(chunk$var),]))

splitデータフレームをチャンクのリストに分割し、最大値を使用して単一行に切り取りを実行し、単一行do.call(rbind,...)のリストを再びデータフレームに縮小します。


1
そしていつものように、これはplyrバージョンよりも約2倍高速です。

1
@mbq、はい、当然ですが、デバッグコストを含めると、通常のデータセットの結果の速度は同じです:) plyrは速度のためではなく、明確さと利便性のために専用です。
mpiktas

とにかくaveの使用は2倍の速さです:)
エドゥアルド・レオニ

2
@Eduardo avelapply+のラッパーでありsplit、コードを確認します(-;

1
@Eduardoええ、しかし、それはすべてを使用してorder、因子内でベクトル化されたソートの風変わりな可能性のためにのみ動作します; より一般的な問題についてsplitは避けられません。

5

使用したい ave

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,3,3,4,2))
## use unique if you want to exclude duplicate maxima
unique(subset(dt, var==ave(var, id, FUN=max)))

+ 1、aveを知りませんでした。Rに表示されたのはいつですか?
mpiktas

1

ベースでこれを行うさらに別の方法:

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))

data.frame(id=sort(unique(dt$var)),max=tapply(dt$var,dt$id,max))
  id max
1  1   4
2  2   3
3  3   4
4  4   2

私はmpiktasのplyrソリューションを好むが。


1

例のように、列varが既に昇順である場合、データフレームを並べ替える必要はありません。duplicated引数を渡す関数を使用するだけfromLast = TRUEであるため、最後の要素を保持して、複製は裏面から考慮されます。

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
z[!duplicated(z$id, fromLast = TRUE), ]

  id var
2  1   4
4  2   3
5  3   5
6  4   2

それ以外の場合は、最初に昇順でデータフレームを並べ替えます。

z <- z[order(z$id, z$var), ]
z[!duplicated(z$id, fromLast = TRUE), ]

dplyrパッケージの使用:

library(dplyr)
z %>%
  group_by(id) %>%
  summarise(var = max(var))

Source: local data frame [4 x 2]    
  id var
1  1   4
2  2   3
3  3   5
4  4   2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.