在没有for循环的情况下实现基于条件的有效数据映射?

时间:2018-07-14 19:22:24

标签: r data.table

我有一个表,该表具有> 1800万行(与多个对象相关的多个事件),并且我试图创建一个关于对象是否具有相同系列事件发生的映射列。

示例数据帧(为了提高效率使用data.table):

aa<-data.table(data.frame(id=c(1,1,1,1,4,4,4,5,5,5,5,5),  val=c("a","a","b","a","c","c","c","a","b","c","a","b")))

对象对应于id列,值是与事件关联的事件发生。

所需的结果,其中noswitch是我的映射列:

    id val noswitch
 1:  1   a       NA
 2:  1   a       NA
 3:  1   b       NA
 4:  1   a       NA
 5:  4   c     TRUE
 6:  4   c     TRUE
 7:  4   c     TRUE
 8:  5   a       NA
 9:  5   b       NA
10:  5   c       NA
11:  5   a       NA
12:  5   b       NA

仅对标记对象的所有事件具有相同值的位置感兴趣

使用for循环执行上述操作的代码:

ids<-unique(aa$id)

aa$noswitch<-rep(NA,nrow(aa))

for ( i in 1: length(ids))
{
  if  ( length(unique(aa[id==ids[i]]$val))==1)  aa[id==ids[i]]$noswitch<-1
}

考虑到原始df的行数和超过200万个对象,使用for循环将需要> 5-6天

是否存在另一种更有效的方法来实现此目标,而又无需拆分数据集并并行运行某些数据集?

2 个答案:

答案 0 :(得分:1)

基于data.table软件包的解决方案。想法是计算每个idval的行数,然后检查该数字是否与每个id的总行数相同。

library(data.table)

aa[, Count := .N, by = .(id, val)][
  , noswitch := Count == .N, by = id][
    , Count := NULL][]
#     id val noswitch
#  1:  1   a    FALSE
#  2:  1   a    FALSE
#  3:  1   b    FALSE
#  4:  1   a    FALSE
#  5:  4   c     TRUE
#  6:  4   c     TRUE
#  7:  4   c     TRUE
#  8:  5   a    FALSE
#  9:  5   b    FALSE
# 10:  5   c    FALSE
# 11:  5   a    FALSE
# 12:  5   b    FALSE

答案 1 :(得分:0)

您还可以利用data.table::uniqueN

library(data.table)
dt[, noswitch := uniqueN(val) == .N, id]

我发现此解决方案更易于阅读,但请注意,它不是第一个解决方案那么快。