【问题标题】:R avoid loop for count with conditionsR避免循环计数条件
【发布时间】:2019-07-08 07:29:42
【问题描述】:

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

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

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

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 如下所示:

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")))

预期的输出是:

   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

您对如何避免循环有任何想法吗?我想过其他的想法,但我的问题总是日期的问题!

【问题讨论】:

  • 你可能想使用非等自连接:data[, countpax := data[data, on=.(firstname, surname, birthday, birthmonth, birthyear, persondatetime&lt;persondatetime), .N, by=.EACHI]]
  • 也许您正在寻找每个组的价值数量。 setDT(df)[, countperson := .N, by = list(firstname, surname, birthday, birthmonth, birthyear, persondatetime)] ?

标签: r performance count data.table


【解决方案1】:

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

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

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

setkey(data, firstname, surname, birthdate, persondatetime)
data[, timebetweenentries := mean(abs(diff(persondatetime)), na.rm=T)

【讨论】:

  • 谢谢!我试过你的代码,它适用于 counperson 变量,但对于 timebetweenentries 它不起作用。我这样尝试过:setkey(data, firstname, surname, birthdate, persondatetime) data[data, on=.(firstname, surname, birthdate=birthdate, persondatetime &gt; persondatetime), timebetweenentries:= mean(abs(diff(persondatetime))), by=.EACHI] 但它只给了我“NA secs”。你知道为什么会这样吗?
  • 抱歉回复晚了,将 na.rm=TRUE 参数添加到 mean 应该可以解决这个问题。 diff 返回第一个值的 NA,因为没有以前的值可以取差。如果任何元素为 NA,则 mean 返回 NA,但可以通过使用 remove na 参数“na.rm”并将其设置为 TRUE 来更改。
猜你喜欢
  • 2021-12-03
  • 1970-01-01
  • 2011-03-20
  • 1970-01-01
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多