【问题标题】:Number equal rows in data.framedata.frame 中相等的行数
【发布时间】:2012-10-25 11:45:00
【问题描述】:

我有一个如下所示的数据框:

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,它是一个基于以下规则的整数:如果df$LogicalTRUE,则为0,或者对于所有行都相同的整数变量ABC 大致相等(因为它们是双精度数,因此在浮点误差范围内),从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,因为LogicalTRUE,第二行和第四行得到1,因为变量ABC在那里大致相等,第二和第五行相同排。第六行得到一个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
  }
}

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

【问题讨论】:

  • 您能否将列ABC 转换为因子?使用示例数据集,看起来就可以了(浮点数的容差问题)

标签: r dataframe plyr


【解决方案1】:

根据下面 Matthew Dowle 的 cmets,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 所写的 here.GRP 在 data.table 1.8.3 中实现,但我仍然使用 1.8.2


从 cmets 跟进,这是 1.8.2 的 NEWS 项目。将添加到?data.table,感谢您的强调!

数字列(double 类型)现在允许在键和 ad hoc by 中使用。 J()SJ() 不再将 double 强制转换为 integeri 加入列 数字类型上的不匹配被强制以静默方式匹配 x 的连接列的类型。 两个浮点值 被认为是相等的(通过分组和二分搜索连接)如果它们 默认情况下,差异在 sqrt(.Machine$double.eps) 内。查看示例 在?unique.data.table。完成 FR #951、#1609 和 #1075。这铺平了 其他使用double 的原子类型的方式(例如POSIXctbit64)。 感谢 Chris Neff 进行 beta 测试并发现密钥问题 两个数字列(错误 #2004),已修复并添加了测试。

【讨论】:

  • 是的,应该可以。我不太明白关于factor 的第一句话。 data.table 内部有代码将double 列分组在机器容差范围内,将double 保持为double。它不会转换为 characterfactor 并且依赖于格式精度,就像 base 一样。有关tan(pi(...)) 的示例,请参阅example(unique.data.table)?data.table 中的文档可以更清楚地说明分组 double 列在机器容差范围内。它使用与all.equal 相同的容差,即.Machine$double.eps ^ 0.5
  • @MatthewDowle,感谢您的澄清。 factor 的东西有点像早期版本的答案。看了example(unique.data.table)后我会澄清的。
  • 好酷。我很惊讶在?data.table 中对double 的分组容差没有任何意义,所以将在...中放一些东西。
  • @MatthewDowle,再次感谢。凭借(很棒!)使用double 列作为关键列的能力,我发现在?data.table 下有信息提到公差(或者它可能在那里但我错过了它......)
  • 哦,从 1.8.2 开始,它才出现在 NEWS 中。我将该项目添加为编辑,并将添加到?data.table...
猜你喜欢
  • 2021-07-17
  • 1970-01-01
  • 2011-12-30
  • 1970-01-01
  • 1970-01-01
  • 2018-03-29
  • 2022-06-10
  • 1970-01-01
  • 2015-02-28
相关资源
最近更新 更多