簡體   English   中英

Select 除一列外所有行都是重復的

[英]Select all rows which are duplicates except for one column

我想在數據集中找到所有列中的值(一列除外)都匹配的行。 在多次嘗試讓 duplicated() 返回重復行的所有實例(而不僅僅是第一個實例)失敗后,我想出了一種方法來做到這一點(如下)。

例如,我想識別 Iris 數據集中除 Petal.Width 之外的所有行。

require(tidyverse)
x = iris%>%select(-Petal.Width)
dups = x[x%>%duplicated(),]
answer =  iris%>%semi_join(dups)

> answer 
   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
1           5.1         3.5          1.4         0.2    setosa
2           4.9         3.1          1.5         0.1    setosa
3           4.8         3.0          1.4         0.1    setosa
4           5.1         3.5          1.4         0.3    setosa
5           4.9         3.1          1.5         0.2    setosa
6           4.8         3.0          1.4         0.3    setosa
7           5.8         2.7          5.1         1.9 virginica
8           6.7         3.3          5.7         2.1 virginica
9           6.4         2.8          5.6         2.1 virginica
10          6.4         2.8          5.6         2.2 virginica
11          5.8         2.7          5.1         1.9 virginica
12          6.7         3.3          5.7         2.5 virginica

如您所見,這是有效的,但這是我幾乎可以肯定很多其他人需要此功能的時候之一,而我不知道一個 function 以更少的步驟或通常更整潔的方式執行此操作. 有什么建議么?

來自至少兩個其他帖子的替代方法適用於這種情況:

answer = iris[duplicated(iris[-4]) | duplicated(iris[-4], fromLast = TRUE),]

但這似乎只是一種不同的解決方法,而不是單一的 function。這兩種方法花費的時間相同。 (在我的系統上為 0.08 秒)。 沒有更整潔/更快的方法嗎?

例如 iris%>%duplicates(all=TRUE,ignore=Petal.Width)

iris[duplicated(iris[,-4]) | duplicated(iris[,-4], fromLast = TRUE),]

在重復行(與第4列無關)中, duplicated(iris[,-4])給出重復集的第二行,第18、35、46、133、143和145行,以及duplicated(iris[,-4], fromLast = TRUE)給出每個重復集的第一行, duplicated(iris[,-4], fromLast = TRUE)和129 | 結果為12 TRUE ,因此返回預期輸出。

或使用dplyr:基本上,您將除Petal.Width之外的所有變量Petal.Width ,計算它們發生的次數,並過濾不止一次出現的那些。

library(dplyr)
iris %>% 
  group_by_at(vars(-Petal.Width)) %>% 
  filter(n() > 1)

   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
          <dbl>       <dbl>        <dbl>       <dbl>    <fctr>
 1          5.1         3.5          1.4         0.2    setosa
 2          4.9         3.1          1.5         0.1    setosa
 3          4.8         3.0          1.4         0.1    setosa
 4          5.1         3.5          1.4         0.3    setosa
 5          4.9         3.1          1.5         0.2    setosa
 6          4.8         3.0          1.4         0.3    setosa
 7          5.8         2.7          5.1         1.9 virginica
 8          6.7         3.3          5.7         2.1 virginica
 9          6.4         2.8          5.6         2.1 virginica
10          6.4         2.8          5.6         2.2 virginica
11          5.8         2.7          5.1         1.9 virginica
12          6.7         3.3          5.7         2.5 virginica

我認為看門人可以直接做到這一點。

library(janitor)

get_dupes(iris, !Petal.Width)

# get_dupes(iris, !Petal.Width)[,names(iris)] # alternative: no count column
   Sepal.Length Sepal.Width Petal.Length   Species dupe_count Petal.Width
1           4.8         3.0          1.4    setosa          2         0.1
2           4.8         3.0          1.4    setosa          2         0.3
3           4.9         3.1          1.5    setosa          2         0.1
4           4.9         3.1          1.5    setosa          2         0.2
5           5.1         3.5          1.4    setosa          2         0.2
6           5.1         3.5          1.4    setosa          2         0.3
7           5.8         2.7          5.1 virginica          2         1.9
8           5.8         2.7          5.1 virginica          2         1.9
9           6.4         2.8          5.6 virginica          2         2.1
10          6.4         2.8          5.6 virginica          2         2.2
11          6.7         3.3          5.7 virginica          2         2.1
12          6.7         3.3          5.7 virginica          2         2.5

我調查了duplicated的來源,但希望知道是否有人可以更快地找到任何東西。 它可能涉及到Rcpp或類似的東西。 在我的機器上,基本方法是最快的,但是您的原始方法實際上比最易讀的dplyr方法dplyr 我認為為自己的目的包裝一個這樣的函數應該足夠了,因為無論如何您的運行時間似乎都不會太長,如果主要是iris %>% opts("Petal.Width") ,則可以這樣做關心。

library(tidyverse)
library(microbenchmark)

opt1 <- function(df, ignore) {
  ignore = enquo(ignore)
  x <- df %>% select(-!!ignore)
  dups <- x[x %>% duplicated(), ]
  answer <- iris %>% semi_join(dups)
}

opt2 <- function(df, ignore) {
  index <-  which(colnames(df) == ignore)
  df[duplicated(df[-index]) | duplicated(df[-index], fromLast = TRUE), ]
}

opt3 <- function(df, ignore){
  ignore <-  enquo(ignore)
  df %>%
    group_by_at(vars(-!!ignore)) %>%
    filter(n() > 1)
}


microbenchmark(
  opt1 = suppressMessages(opt1(iris, Petal.Width)),
  opt2 = opt2(iris, "Petal.Width"),
  opt3 = opt3(iris, Petal.Width)
)
#> Unit: milliseconds
#>  expr      min       lq     mean   median       uq       max neval cld
#>  opt1 3.427753 4.024185 4.851445 4.464072 5.069216 12.800890   100  b 
#>  opt2 1.712975 1.908130 2.403859 2.133632 2.542871  7.557102   100 a  
#>  opt3 6.604614 7.334304 8.461424 7.920369 8.919128 24.255678   100   c

reprex軟件包 (v0.2.0)於2018-07-12創建。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM