这是我的问题。我有一个20万行的数据集。
我想为每个测试分配一个索引。例如。主题1的第一次测试将是1,主题1的第二次测试将是2.主题2的第一次测试将是1等。
我的策略是获取唯一主题ID的列表,使用lapply将数据集子集化为使用唯一主题ID的数据帧列表,每个主题具有他/她自己的数据帧并进行测试。理想情况下,我可以对每个主题的每个数据框进行排序,并为每个测试分配一个索引。
然而,在200k x 32的数据帧上进行此操作使我的笔记本电脑(i5,Sandy Bridge,4GB内存)很快耗尽内存。
我有两个问题:
以下是生成一些虚拟数据的代码:
UniqueSubjectID <- sapply(1:500, function(i) paste(letters[sample(1:26, 5, replace = TRUE)], collapse =""))
UniqueSubjectID <- subset(UniqueSubjectID, !duplicated(UniqueSubjectID))
Dataset <- data.frame(SubID = sample(sapply(1:500, function(i) paste(letters[sample(1:26, 5, replace = TRUE)], collapse ="")),5000, replace = TRUE))
Dates <- sample(c(dates = format(seq(ISOdate(2010,1,1), by='day', length=365), format='%d.%m.%Y')), 5000, replace = TRUE)
Dataset <- cbind(Dataset, Dates)
答案 0 :(得分:5)
我猜测分裂/ lapply正在耗尽内存。您应该考虑采用更加矢量化的方法。从示例代码的略微修改版本开始:
n <- 200000
UniqueSubjectID <- replicate(500, paste(letters[sample(26, 5, replace=TRUE)], collapse =""))
UniqueSubjectID <- unique(UniqueSubjectID)
Dataset <- data.frame(SubID = sample(UniqueSubjectID , n, replace = TRUE))
Dataset$Dates <- sample(c(dates = format(seq(ISOdate(2010,1,1), by='day', length=365), format='%d.%m.%Y')), n, replace = TRUE)
假设您想要的是按主题按日期顺序计算测试的索引,您可以执行以下操作。
Dataset <- Dataset[order(Dataset$SubID, Dataset$Dates), ]
ids.rle <- rle(as.character(Dataset$SubID))
Dataset$SubIndex <- unlist(sapply(ids.rle$lengths, function(n) 1:n))
现在,“数据集”中的“SubIndex”列包含测试的副主题编号索引。这需要非常少的内存,并在我的4GB Core 2 duo笔记本电脑上运行几秒钟。
答案 1 :(得分:4)
这听起来像plyr
包的工作。我会以这种方式添加索引:
require(plyr)
system.time(new_dat <- ddply(Dataset, .(SubID), function(dum) {
dum = dum[order(dum$SubID, dum$Dates), ]
mutate(dum, index = 1:nrow(dum))
}))
这会将数据集拆分为每个SubID
的块,并添加索引。新对象将所有SubID
组合在一起,并按时间排序。你的例子在我的机器上花了大约2秒钟,并且几乎没有使用任何内存。我不确定ddply
如何缩放您的数据大小和特征,但您可以尝试。我的速度不够快,一定要查看data.table
包。与ddply
和data.table
进行比较的blog post of mine可以作为一些灵感。