我将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 <- 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
您对我如何避免循环有任何想法吗?我想到了其他想法,但我的问题总是与日期有关!
答案 0 :(得分:1)
您可以使用类似于@ chinsoon12在其评论中发布的代码来重新创建计数人员列。
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
中的每一行,.N
是X
中基于conditions
进行匹配的行数。如果I
中的行在X
中没有匹配的行,则.N
为NA,我们在下一行中使用合并将其设置为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)