3

我有一个看起来像这样的数据框:

df <- data.frame(
  Logical = c(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE),
  A = c(1,2,3,2,3,1),
  B = c(1,0.05,0.80,0.05,0.80,1),
  C = c(1,10.80,15,10.80,15,1))

看起来像:

  Logical A    B    C
1    TRUE 1 1.00  1.0
2   FALSE 2 0.05 10.8
3   FALSE 3 0.80 15.0
4   FALSE 2 0.05 10.8
5   FALSE 3 0.80 15.0
6   FALSE 1 1.00  1.0

我想添加一个新变量 ,D它是基于以下规则的整数:0如果df$LogicalTRUE,或者对于所有变量行都相同的整数,A并且B大约C是(因为它们是双精度数,所以在一个浮点误差)相等,从 开始1

这里的预期输出:

  Logical A    B    C D
1    TRUE 1 1.00  1.0 0
2   FALSE 2 0.05 10.8 1
3   FALSE 3 0.80 15.0 2
4   FALSE 2 0.05 10.8 1
5   FALSE 3 0.80 15.0 2
6   FALSE 1 1.00  1.0 3

第一行是0因为Logicalis TRUE,第二行和第四行1是因为变量AB并且C在那里近似相等,第二行和第五行相同。第六行得到 a 3,因为它是下一个唯一的行。请注意,分配的整数顺序D无关紧要,除了0. 例如,也可以分配第 2 行和第 4 行2,只要该整数在D.


我考虑过使用聚合函数。例如使用ddply

library("plyr")
df$foo <- 1:nrow(df)
foo <- dlply(df,.(A,B,C),'[[',"foo")
df$D <- 0
for (i in 1:length(foo)) df$D[foo[[i]]] <- i
df$D[df$Logical] <- 0

有效,但我不确定这对浮点错误有多大影响(我想我可以在此调用之前对此处的值进行四舍五入,但它应该相当稳定)。使用循环很容易:

df$D <- 0
c <- 1
for (i in 1:nrow(df))
{
  if (!isTRUE(df$Logical[i]) & df$D[i]==0)
  {
    par <- sapply(1:nrow(df),function(j)!df$Logical[j]&isTRUE(all.equal(unlist(df[j,c("A" ,"B", "C")]),unlist(df[i,c("A" ,"B", "C")]))))
    df$D[par] <- c
    c <- c+1
  }
}

但这对于较大的数据帧来说非常慢。

4

1 回答 1

4

根据下面 Matthew Dowle 的评论,可以对数值进行分组,并用公差data.table区分它们。.Machine$double.eps^.5考虑到这一点,data.table解决方案应该有效:

library(data.table)

DT <- as.data.table(df)

DT[, D := 0]

.GRP <- 0

DT[!Logical, D := .GRP <- .GRP + 1, by = "A,B,C"]

#    Logical A    B    C foo D
# 1:    TRUE 1 1.00  1.0   1 0
# 2:   FALSE 2 0.05 10.8   2 1
# 3:   FALSE 3 0.80 15.0   3 2
# 4:   FALSE 2 0.05 10.8   4 1
# 5:   FALSE 3 0.80 15.0   5 2
# 6:   FALSE 1 1.00  1.0   6 3

正如 Matthew Dowle 在这里所写,.GRP在 data.table 1.8.3 中实现,但我仍然使用 1.8.2


跟进评论,这是 1.8.2 的 NEWS 项目。将添加到?data.table,感谢突出显示!

double现在允许在键和临时 by 中使用 数字列(类型)。J()并且SJ()不再强求double。与数字类型不匹配的连接列被强制以静默方式匹配 的连接列的类型。默认情况下,如果两个浮点值的差异在 sqrt(.Machine$double.eps) 范围内,则认为两个浮点值相等(通过分组和二分搜索连接)。请参见 中的示例。完成 FR #951、#1609 和 #1075。这为其他使用的原子类型(例如和)铺平了道路。感谢 Chris Neff 进行 beta 测试并发现两个数字列的键的问题(错误 #2004),已修复并添加了测试。integerix?unique.data.tabledoublePOSIXctbit64

于 2012-10-25T12:26:18.803 回答