首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >R避免循环for count with conditions

R避免循环for count with conditions
EN

Stack Overflow用户
提问于 2019-07-08 15:29:42
回答 1查看 128关注 0票数 1

我将R与data.table包一起使用。我有一个计算计数的循环,但由于它是一个循环,所以速度非常慢。现在我想以某种方式改变它,这样它就不需要几天的时间来计算了。

我有一个数据集,我想计算这个人在数据集中出现的频率。当名字、姓氏和出生日期(生日、出生月份和生日)相同时,它是相同的“人”。然而,我的问题是,日期也很重要。因此,如果我正在查看的这个人出现在数据集中,我必须检查“同一个人”的日期是否在我正在查看的人的日期之前。因此,同一个人必须在我看到的人之前知道。

然后我还想计算这些条目之间的平均时间。以下是我目前的解决方案(工作有效,但速度非常慢):

代码语言:javascript
复制
library(data.table)
data <- data[order(-persondatetime)]
vec_countperson <- numeric(nrow(data))
vec_time <- numeric(nrow(data))

for (i in 1:nrow(data)){
  vec_countperson[i] <- data[firstname == data[i, firstname] &
                                   surname == data[i, surname] &
                                   birthdate == data[i, birthdate] &
                                   persondatetime < data[i, persondatetime], .N]
       vec_time[i] <- data[firstname == data[i, firstname] &
                                   surname == data[i, surname] &
                                   birthdate == data[i, birthdate] &
                                   persondatetime < data[i, persondatetime], 
                                   mean(abs(diff(c(persondatetime, data[i, persondatetime]))))]
}


data[, countperson := vec_countperson]
data[, timebetweenentries := vec_time]

示例data.table将如下所示:

代码语言:javascript
复制
data <- data.table(
  firstname = c("Paul", "Jens", "Jens", "Jens","Paul", "Dieter"), 
  surname = c("Mueller", "Mustermann", "Mustermann", "Mustermann", "Mueller", "Brian"), 
  birthdate = as.Date(c("1960-05-08", "1960-05-08", "1960-05-08",
                        "1960-05-08", "1960-05-08", "1960-05-08")), 
  persondatetime = as.POSIXct(c("2018-05-01 23:18:38 CET", "2018-03-01 23:18:38 CET",
                                "2018-06-01 23:18:38 CET", "2018-04-01 23:18:38 CET", 
                                "2018-04-06 23:18:38 CET", "2018-04-08 23:18:38 CET")))

预期输出为:

代码语言:javascript
复制
   firstname    surname  birthdate      persondatetime countperson timebetweenentries
1:      Jens Mustermann 1960-05-08 2018-03-01 23:18:38           0                NaN
2:      Jens Mustermann 1960-05-08 2018-04-01 23:18:38           1           30.95833
3:      Paul    Mueller 1960-05-08 2018-04-06 23:18:38           0                NaN
4:    Dieter      Brian 1960-05-08 2018-04-08 23:18:38           0                NaN
5:      Paul    Mueller 1960-05-08 2018-05-01 23:18:38           1           25.00000
6:      Jens Mustermann 1960-05-08 2018-06-01 23:18:38           2           45.97917

你知道我怎么才能避免这个循环吗?我想过其他的想法,但我的问题总是与日期有关!

EN

回答 1

Stack Overflow用户

发布于 2019-07-09 12:43:18

您可以使用类似于@chinsoon12在他的评论中发布的代码来重新创建countperson列。

代码语言:javascript
复制
data[data, 
     on=.(firstname, surname, birthdate=birthdate, persondatetime > persondatetime),
     countperson:=.N, 
     by=.EACHI]
data[, countperson := coalesce(countperson, 0L)]

此更新联接的data.table语法为X[I, on=.(conditions), var:=.N, by=.EACHI]。对于data.table I中的每一行,都会找到X匹配conditions中的行。使用by=.EACHI参数按I中的行对此连接的结果进行分组。在data.table中,.N符号表示每个组的行数。在本例中,对于I中的每一行,.NX中基于conditions匹配的行数。如果I中的某一行在X中没有匹配的行,则.N为NA,我们在下一行中使用coalesce将其设置为0。

重新创建timebetweenentries变量的一种方法是按指示行属于同一个person的列进行分组,计算每个组的persondatetime的平均差异,并将其分配给data.table中的一列。如果您想要连续条目之间的时间,那么您应该在获得差异之前对persondatetime进行排序。

下面的代码使用data.table的setkey函数一次完成所有排序。这应该会加快分组速度,并避免为每个组调用sort(persondatetime)。

代码语言:javascript
复制
setkey(data, firstname, surname, birthdate, persondatetime)
data[, timebetweenentries := mean(abs(diff(persondatetime)), na.rm=T)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56930207

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档