在避免循环的同时计算比其他行数 "smaller" 的行数

Counting number of rows "smaller" than other rows while avoiding loop

我需要根据列值计算与特定行不同的行数,同时避免循环解决方案。

示例:拿一个 data.table 对象 A 有四行,每行代表一个人。 每个人有 3 个值 v1, v2, v3。 objective是统计,对于一个特定的个体(行),有多少其他个体的所有三个变量的值都严格大于(或等于),在变量count中统计。 完成这项工作的循环版本可能是:

A = data.table(matrix(0,  nrow = 4, ncol = 3))

colnames(A) <- c("v1","v2","v3")

# Assign values for variables v1, v2, v3
A[1,1] <- 1; A[1,2] <- 1; A[1,3] <- 1
A[2,1] <- 1; A[2,2] <- 1.5; A[2,3] <- 1
A[3,1] <- 0.9; A[3,2] <- 0.5; A[3,3] <- 0.8
A[4,1] <- 2; A[4,2] <- 1.5; A[4,3] <- 2

# Count variable 
A$count = NA

for(j in 1:nrow(A)){
  A$count[j] = 0
  A$count[j] = 0    
  for(k in 1:nrow(A)){
    # Compares the value(s) of individual j relatively to individual k
    if( ( A$v1[j] < A$v1[k] ) & ( A$v2[j] < A$v2[k] ) & ( A$v3[j] < A$v3[k] ) ){
      A$count[j] = A$count[j]+1    } # if condition above is fullfilled, add 1 
    
  }
}

产生结果:

    v1  v2  v3 count
1: 1.0 1.0 1.0     1
2: 1.0 1.5 1.0     0
3: 0.9 0.5 0.8     3
4: 2.0 1.5 2.0     0

想法如何通过获得相同的结果来避免 时间密集循环

你可以使用自己 ​​non-equi join:

A[A,.(v1=i.v1,v2=i.v2,v3=i.v3,x.v1),on=.(v1>v1,v2>v2,v3>v3)][
  ,.(count=sum(!is.na(x.v1))),by=.(v1,v2,v3)]

    v1  v2  v3 count
1: 1.0 1.0 1.0     1
2: 1.0 1.5 1.0     0
3: 0.9 0.5 0.8     3
4: 2.0 1.5 2.0     0

有一个特殊的符号 .EACHI,它允许 由每个 i 在连接中分组。因此,我们可以同时加入和聚合,即使在 非等自加入:

A[A, on = .(v1>v1, v2>v2, v3>v3), .N, by = .EACHI]
    v1  v2  v3 N
1: 1.0 1.0 1.0 1
2: 1.0 1.5 1.0 0
3: 0.9 0.5 0.8 3
4: 2.0 1.5 2.0 0

.EACHI更详细的解释,请看this answer