在数据框中高效地查找具有几乎相同值的行组

Efficiently find groups of rows in a data frame with almost identical values

我有大约一千行的数据集,但它会增长。 我想找到一定数量的属性几乎相同的行组。

我可以做一个愚蠢的暴力搜索,但它真的很慢,我相信 R 可以做得更好。

测试数据:

df = read.table(text="
      Date     Time  F1   F2   F3   F4   F5 Conc
2010-06-23 04:00:00 0.1 17.6 14.2 19.5 18.6 16.1
2010-12-16 00:20:00 0.0 28.7 13.7 15.6 16.2 14.4
2010-12-16 10:30:00 0.0 17.0 14.0 19.0 18.0 16.0
2010-12-16 22:15:00 0.0 25.5 12.6 14.9 16.6 16.8
", header=T)


#Initialize column to hold clustering info
df$cluster = NA

#Maximum tolerance for a match between rows 
toler=1.0

#Brute force search, very ugly.
for(i in 1:(nrow(df)-1)){
    if(is.na(df$cluster[i])){
        df$cluster[i] <- i
        for(j in (i+1):nrow(df)){
            if(max(abs(df[i,3:7] - df[j,3:7]))<toler){
                df$cluster[j]<-i
            }
        }
    }
}
if(is.na(df$cluster[j])){df$cluster[j] <- j}

df

预期输出:

        Date     Time  F1   F2   F3   F4   F5 Conc cluster
1 2010-06-23 04:00:00 0.1 17.6 14.2 19.5 18.6 16.1       1
2 2010-12-16 00:20:00 0.0 28.7 13.7 15.6 16.2 14.4       2
3 2010-12-16 10:30:00 0.0 17.0 14.0 19.0 18.0 16.0       1
4 2010-12-16 22:15:00 0.0 25.5 12.6 14.9 16.6 16.8       4

这是一个使用 data.table 的选项:

df[, (cols) := c(.SD-1, .SD+1), .SDcols=fcols]
onstr <- c(paste0(fcols,">",cols[rng]),paste0(fcols,"<",cols[5+rng]))
df[, cluster := df[df, on=onstr, by=.EACHI, min(x.rn)]$V1]

输出:

         Date     Time  F1   F2   F3   F4   F5 Conc rn lower1 lower2 lower3 lower4 lower5 upper1 upper2 upper3 upper4 upper5 cluster
1: 2010-06-23 04:00:00 0.1 17.6 14.2 19.5 18.6 16.1  1   -0.9   16.6   13.2   18.5   17.6    1.1   18.6   15.2   20.5   19.6       1
2: 2010-12-16 00:20:00 0.0 28.7 13.7 15.6 16.2 14.4  2   -1.0   27.7   12.7   14.6   15.2    1.0   29.7   14.7   16.6   17.2       2
3: 2010-12-16 10:30:00 0.0 17.0 14.0 19.0 18.0 16.0  3   -1.0   16.0   13.0   18.0   17.0    1.0   18.0   15.0   20.0   19.0       1
4: 2010-12-16 22:15:00 0.0 25.5 12.6 14.9 16.6 16.8  4   -1.0   24.5   11.6   13.9   15.6    1.0   26.5   13.6   15.9   17.6       4

数据:

df = read.table(text="
      Date     Time  F1   F2   F3   F4   F5 Conc
2010-06-23 04:00:00 0.1 17.6 14.2 19.5 18.6 16.1
2010-12-16 00:20:00 0.0 28.7 13.7 15.6 16.2 14.4
2010-12-16 10:30:00 0.0 17.0 14.0 19.0 18.0 16.0
2010-12-16 22:15:00 0.0 25.5 12.6 14.9 16.6 16.8
", header=T)

library(data.table)
setDT(df)[, rn := .I]
toler <- 1.0
rng <- 1L:5L
fcols <- paste0("F", rng)
cols <- do.call(paste0, CJ(c("lower", "upper"), rng))

解释:

    整数后面的
  • L 告诉 R 这是整数类型(参见 Why would R use the "L" suffix to denote an integer?

  • df[df, on=onstr, by=.EACHI, min(x.rn)] 正在使用 onstr.

  • 中指定的不等式执行非等自连接
  • $V1访问上面join的V1列(不提供时命名默认为V*)

  • df[, cluster := my_result] 通过引用更新原始的 data.table 以便在数据集较大时速度更快。改进是由于不需要像在基础 R 中那样对原始 data.frame 进行深度复制。

  • 因为我们正在执行连接,所以有左 table 和右 table。在 data.table 术语中,对于 x[i, on=join_keys]x 是右 table,i 是左 table(灵感来自基础 R 语法)。因此,x. 用于引用左侧 table 中的访问列,类似于 SQL 语法,类似地用于 i.。可以在 data.table 小插图中找到更多详细信息。 (参见 https://cran.r-project.org/web/packages/data.table/