【问题标题】:Remove (quasi) identical rows删除(准)相同的行
【发布时间】:2019-03-26 12:24:04
【问题描述】:

在下面的 data.df 中,我们看到第 2 行和第 3 行是相同的,只是第 4 行的平均值不同。

    iso3 dest   code year          uv       mean
1    ALB  AUT 490700 2002  14027.2433 427387.640
2    ALB  BGR 490700 2002   1215.5613  11886.494
3    ALB  BGR 490700 2002   1215.5613  11886.494
4    ALB  BGR 490700 2002   1215.5613  58069.405
5    ALB  BGR 843050 2002    677.9827   4272.176
6    ALB  BGR 851030 2002  31004.0946  32364.379
7    ALB  HRV 392329 2002   1410.0072   6970.930

有什么简单的方法可以自动找到这些相同的行吗? 我发现this subject 似乎可以回答这个问题,但我不明白 'duplicated()` 是如何工作的......

我想要的是一个“简单”的命令,我可以在其中精确地逐行确定哪一列的值应该是相同的。 类似:function(data.df, c(iso3, dest, code, year, uv, mean)) 找到完全相同的行和function(data.df, c(iso3, dest, code, year, uv)) 找到“准”相同的行......

在第一种情况下,预期的结果类似于:

2    ALB  BGR 490700 2002   1215.5613  11886.494
3    ALB  BGR 490700 2002   1215.5613  11886.494

在第二个中:

2    ALB  BGR 490700 2002   1215.5613  11886.494
3    ALB  BGR 490700 2002   1215.5613  11886.494
4    ALB  BGR 490700 2002   1215.5613  58069.405

有什么想法吗?

【问题讨论】:

  • 你应该试试dplyr::distinct(data.df, iso3, dest, code, year, uv, .keep_all =TRUE)

标签: r


【解决方案1】:

我们可以编写一个函数,然后传递我们想要考虑的列。

get_duplicated_rows <- function(df, cols) {
  df[duplicated(df[cols]) | duplicated(df[cols], fromLast = TRUE), ]
}

get_duplicated_rows(df, c("iso3", "dest", "code", "year", "uv","mean"))

# iso3 dest   code year     uv  mean
#2  ALB  BGR 490700 2002 1215.6 11886
#3  ALB  BGR 490700 2002 1215.6 11886

get_duplicated_rows(df, c("iso3", "dest", "code", "year", "uv"))
#  iso3 dest   code year     uv  mean
#2  ALB  BGR 490700 2002 1215.6 11886
#3  ALB  BGR 490700 2002 1215.6 11886
#4  ALB  BGR 490700 2002 1215.6 58069

【讨论】:

  • 如果我想删除重复项?一旦他们被识别,你知道一个简单的方法吗? (为了只保留其中一个……)
  • @TeYaP 如果您只想保留其中一个重复项,请从函数中删除 | duplicated(df[cols], fromLast = TRUE 部分,它将只保留一行。
【解决方案2】:

如果您逐个查看每个特征,然后考虑 Rowsum 大于您的目标值的行,您可以获得准重复。

toread <- "    iso3 dest   code year          uv       mean
    ALB  AUT 490700 2002  14027.2433 427387.640
    ALB  BGR 490700 2002   1215.5613  11886.494
    ALB  BGR 490700 2002   1215.5613  11886.494
    ALB  BGR 490700 2002   1215.5613  58069.405
    ALB  BGR 843050 2002    677.9827   4272.176
    ALB  BGR 851030 2002  31004.0946  32364.379
    ALB  HRV 392329 2002   1410.0072   6970.930"

df <- read.table(textConnection(toread), header = TRUE) 
closeAllConnections()

get_quasi_duplicated_rows <- function(df, cols, cut){
  result <- matrix(nrow = nrow(df), ncol = length(cols))
  colnames(result) <- cols
  for(col in cols){
    dup <- duplicated(df[col]) | duplicated(df[col], fromLast = TRUE)
    result[ , col] <- dup
  }
  return(df[which(rowSums(result) > cut), ])
}

get_quasi_duplicated_rows(df, c("iso3", "dest", "code", "year", "uv","mean"), 4)


 iso3 dest   code year       uv     mean
2  ALB  BGR 490700 2002 1215.561 11886.49
3  ALB  BGR 490700 2002 1215.561 11886.49
4  ALB  BGR 490700 2002 1215.561 58069.40

【讨论】:

    【解决方案3】:

    使用dplyrrlang 包我们可以实现这一点-

    解决方案-

    find_dupes <- function(df,cols){
      df <- df %>% get_dupes(!!!rlang::syms(cols))
      return(df)
    }
    

    输出-

    第一种情况-

    > cols
    [1] "iso3" "dest" "code" "year" "uv" 
    
    > find_dupes(df, cols)
    
    # A tibble: 3 x 7
      iso3  dest    code  year    uv dupe_count   mean
      <fct> <fct>  <int> <int> <dbl>      <int>  <dbl>
    1 ALB   BGR   490700  2002 1216.          3 11886.
    2 ALB   BGR   490700  2002 1216.          3 11886.
    3 ALB   BGR   490700  2002 1216.          3 58069.
    

    第二种情况-

    > cols
    [1] "iso3" "dest" "code" "year" "uv"   "mean"
    
    > find_dupes(df,cols)
    
    # A tibble: 2 x 7
      iso3  dest    code  year    uv   mean dupe_count
      <fct> <fct>  <int> <int> <dbl>  <dbl>      <int>
    1 ALB   BGR   490700  2002 1216. 11886.          2
    2 ALB   BGR   490700  2002 1216. 11886.          2
    

    注意-

    rlan::syms 函数将字符串作为输入并将它们转换为符号。与 as.name() 不同,它们预先将字符串转换为本机编码。这是必要的,因为符号会默默地删除字符串的编码标记。

    要在dplyr 函数中传递向量名称列表,我们使用syms

    !!! 用于取消引用

    【讨论】:

      【解决方案4】:

      我们可以使用group_by_all 并过滤频率计数超过1个

      library(dplyr)
      df1 %>%
         group_by_all() %>% 
         filter(n() > 1)
      # A tibble: 2 x 6
      # Groups:   iso3, dest, code, year, uv, mean [1]
      #  iso3  dest    code  year    uv   mean
      #  <chr> <chr>  <int> <int> <dbl>  <dbl>
      #1 ALB   BGR   490700  2002 1216. 11886.
      #2 ALB   BGR   490700  2002 1216. 11886.
      

      如果是列的子集,请使用group_by_at

      df1 %>%
           group_by_at(vars(iso3, dest, code, year, uv)) %>%
           filter(n() > 1)
      # A tibble: 3 x 6
      # Groups:   iso3, dest, code, year, uv [1]
      #  iso3  dest    code  year    uv   mean
      #  <chr> <chr>  <int> <int> <dbl>  <dbl>
      #1 ALB   BGR   490700  2002 1216. 11886.
      #2 ALB   BGR   490700  2002 1216. 11886.
      #3 ALB   BGR   490700  2002 1216. 58069.
      

      【讨论】:

        猜你喜欢
        • 2017-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多