「添え字の小さい要素」を含むすべての重複行の検索


111

R duplicatedは、ベクトルまたはデータフレームの各要素が、添え字の小さい要素の複製かどうかを示すベクトルを返します。したがって、5行のデータフレームの行3、4、および5が同じであるduplicated場合、ベクトルを取得します

FALSE, FALSE, FALSE, TRUE, TRUE

しかし、この場合、私は実際に取得したい

FALSE, FALSE, TRUE, TRUE, TRUE

つまり、添え字の大きい行によって行が重複しているかどうかを知りたいのです。

回答:


128

duplicatedfromLast議論があります。の「例」セクションで?duplicatedは、その使用方法を示します。呼び出すだけduplicatedで1回、二回fromLast=FALSEで1回fromLast=TRUEとされているかの行を取りますTRUE


後半の編集:再現可能な例を提供しなかったので、@ jbaumsによる親切なイラストをここに示します

vec <- c("a", "b", "c","c","c") 
vec[duplicated(vec) | duplicated(vec, fromLast=TRUE)]
## [1] "c" "c" "c"

編集:データフレームの場合の例:

df <- data.frame(rbind(c("a","a"),c("b","b"),c("c","c"),c("c","c")))
df[duplicated(df) | duplicated(df, fromLast=TRUE), ]
##   X1 X2
## 3  c  c
## 4  c  c

3
ちょっと待って、私はテストを実行したところ、私が間違っていたことがわかりました。7、8 x <- c(1:9, 7:10, 5:22); y <- c(letters, letters[1:5]); test <- data.frame(x, y); test[duplicated(test$x) | duplicated(test$x, fromLast=TRUE), ]、および9の彼の3つのコピーすべてを返しました。なぜそれが機能するのですか?
JoeM05

1
真ん中のものは最後から始めても正面から撮っても構いません。例えば、duplicated(c(1,1,1))VSがduplicated(c(1,1,1,), fromLast = TRUE)与えられるc(FALSE,TRUE,TRUE)c(TRUE,TRUE,FALSE)TRUEどちらの場合も中間値です。撮影|両ベクターのことはできますc(TRUE,TRUE,TRUE)
ブランドン

34

duplicated値のセットを組み立て、適用uniqueしてから、でテストする必要があります%in%。いつものように、サンプル問題はこのプロセスを生き生きとさせます。

> vec <- c("a", "b", "c","c","c")
> vec[ duplicated(vec)]
[1] "c" "c"
> unique(vec[ duplicated(vec)])
[1] "c"
>  vec %in% unique(vec[ duplicated(vec)]) 
[1] FALSE FALSE  TRUE  TRUE  TRUE

同意します。処理速度が低下する可能性もありますが、非常に遅くなることはほとんどありません。
IRTFM 2018年

かなり本当です。OPは、データフレーム内の「これまでに重複した」行をテストするためのデータ例を提供していませんでした。私は使用しての私の提案を考えてduplicateduniqueそして%in%1は最初にした場合、容易にデータフレームに一般化することができpaste、異常な区切り文字で各列。(受け入れられた回答の方が優れています。)
IRTFM '

3

私は同じ質問をしました、そして私が間違っていなければ、これも答えです。

vec[col %in% vec[duplicated(vec$col),]$col]

Dunnoの方が高速ですが、現在使用しているデータセットは、大きな時間ギャップを生み出すテストを実行するのに十分な大きさではありません。


1
この回答はvec、原子ベクトルとデータフレームの両方として使用されているようです。実際のdatframeでは失敗するのではないかと思います。
IRTFM 2018年

3

データフレーム内で重複行がで得ることができたdplyrことにより、

df = bind_rows(iris, head(iris, 20)) # build some test data
df %>% group_by_all() %>% filter(n()>1) %>% ungroup()

特定の列を除外するgroup_by_at(vars(-var1, -var2))代わりに、データをグループ化するために使用できます。

データだけでなく行インデックスが実際に必要な場合は、最初に次のように追加できます。

df %>% add_rownames %>% group_by_at(vars(-rowname)) %>% filter(n()>1) %>% pull(rowname)

1
の素敵な使い方n()。結果のデータフレームをグループ解除することを忘れないでください。
qwr

@qwr結果をグループ化しないように回答を調整しました
Holger Brandl

2

これが関数としての@Joshua Ulrichのソリューションです。このフォーマットでは、duplicated()を使用するのと同じ方法でこのコードを使用できます。

allDuplicated <- function(vec){
  front <- duplicated(vec)
  back <- duplicated(vec, fromLast = TRUE)
  all_dup <- front + back > 0
  return(all_dup)
}

同じ例を使用します:

vec <- c("a", "b", "c","c","c") 
allDuplicated(vec) 
[1] FALSE FALSE  TRUE  TRUE  TRUE

0

特定の列でどの行が複製されるかに興味がある場合は、plyrアプローチを使用できます。

ddply(df, .(col1, col2), function(df) if(nrow(df) > 1) df else c())

dplyrを使用してcount変数を追加します。

df %>% add_count(col1, col2) %>% filter(n > 1)  # data frame
df %>% add_count(col1, col2) %>% select(n) > 1  # logical vector

重複する行の場合(すべての列を考慮):

df %>% group_by_all %>% add_tally %>% ungroup %>% filter(n > 1)
df %>% group_by_all %>% add_tally %>% ungroup %>% select(n) > 1

これらのアプローチの利点は、カットオフとして重複の数を指定できることです。


0

同様の問題がありましたが、特定の列の値によって重複した行を識別する必要がありました。私は次のdplyrソリューションを思いつきました:

df <- df %>% 
  group_by(Column1, Column2, Column3) %>% 
  mutate(Duplicated = case_when(length(Column1)>1 ~ "Yes",
                            TRUE ~ "No")) %>%
  ungroup()

コードは行を特定の列でグループ化します。グループの長さが1より大きい場合、コードはグループ内のすべての行を重複としてマークします。これが完了すると、Duplicated列をフィルタリングなどに使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.