以更快的方式计算 R 中列中不同 id 的特征
Posted
技术标签:
【中文标题】以更快的方式计算 R 中列中不同 id 的特征【英文标题】:Count features for different ids in columns in R in faster way 【发布时间】:2014-07-09 04:02:39 【问题描述】:我正在尝试在 R 中处理一个 20 GB 的数据文件。我有 16 GB 的 RAM 和 i7 处理器。我正在使用以下方法读取数据:
y<-read.table(file="sample.csv", header = TRUE, sep = ",", skip =0, nrows =50000000)
数据集'y'如下:
id feature
21 234
21 290
21 234
21 7802
21 3467
21 234
22 235
22 235
22 1234
22 236
22 134
23 9133
23 223
23 245
23 223
23 122
23 223
以上是示例数据集,它显示了特定 id 的不同特征。我想计算另一个数据集 x 中列出的特定特征对于 y 中的 id 出现了多少次。
数据集x如下:
id feature
21 234
22 235
23 223
我想要的最终输出如下:
id feature_count
21 3
22 2
23 3
我们看到 234 在 21 中出现了三次,235 在 22 中出现了两次,223 在 23 中出现了两次。
为此,我尝试获取新 id 开始的位置:(例如,上述示例的第 1、第 7 和第 12 位置),然后使用 for 循环计算特征,如下所示:
获取不同id的位置
positions=0
positions[1]=1
j=2
for(i in 1:50000000)
if(y$id[i]!=y$id[i+1])
positions[j]=i+1
j=j+1
由于数据量很大,因此循环需要花费大量时间。(对于 5000 万行,在上述配置 PC 上需要 321 秒,而我有 3 亿行)。
计算与 'x' 中给定特征匹配的特征。(x 是上面指定的数据框,特征将从该数据框与 y 的特征匹配。匹配时 feature_count 增加)
for(i in 1 :length(positions))
for(j in positions[i]:positions[i+1])
if(y$feature[j]==x$feature[i])
feature_count[i]=feature_count[i]+1
是否有任何 R 函数可以在更快的时间内为我共同完成这项工作。 同样使用“positions[i]:positions[i+1]”递增 for 循环会引发错误,指出 for 循环中的 NA 参数。请提出一个正确的方法来做到这一点。
【问题讨论】:
【参考方案1】:我承认我并不真正理解问题的编写方式,但听起来“data.table”将是可行的方法,您应该查看.N
函数。正如已经提到的fread
将比read.csv
好得多,所以我假设您已经将数据读入名为“DT”的data.table
。
这是一个小的:
DT <- data.table(id = c(rep(21, 6), rep(22, 5), 23, 23),
feature = c(234, 290, 234, 7802, 3467, 234, 235,
235, 1234, 236, 134, 9133, 223))
DT
# id feature
# 1: 21 234
# 2: 21 290
# 3: 21 234
# 4: 21 7802
# 5: 21 3467
# 6: 21 234
# 7: 22 235
# 8: 22 235
# 9: 22 1234
# 10: 22 236
# 11: 22 134
# 12: 23 9133
# 13: 23 223
如果您只想计算每个独特功能的数量,您可以这样做:
DT[, .N, by = "id,feature"]
# id feature N
# 1: 21 234 3
# 2: 21 290 1
# 3: 21 7802 1
# 4: 21 3467 1
# 5: 22 235 2
# 6: 22 1234 1
# 7: 22 236 1
# 8: 22 134 1
# 9: 23 9133 1
# 10: 23 223 1
如果你想要first“特征”的计数,通过“id”,你可以使用:
DT[, .N, by = "id,feature"][, .SD[1], by = "id"]
# id feature N
# 1: 21 234 3
# 2: 22 235 2
# 3: 23 9133 1
如果您想通过“id”获取最常出现的“特征”(在这种情况下与上面的结果相同),您可以尝试以下操作:
DT[, .N, by = "id,feature"][, lapply(.SD, function(x) x[which.max(N)]), by = "id"]
更新
根据您的新描述,这似乎容易多了。
只需merge
您的数据集和aggregate
计数。再次,在“data.table”中快速完成:
DTY <- data.table(y, key = "id,feature")
DTX <- data.table(x, key = "id,feature")
DTY[DTX][, .N, by = id]
# id N
# 1: 21 3
# 2: 22 2
# 3: 23 3
或者:
DTY[, .N, by = key(DTY)][DTX]
# id feature N
# 1: 21 234 3
# 2: 22 235 2
# 3: 23 223 3
这是假设“x”和“y”定义如下:
x <- structure(list(id = 21:23, feature = c(234L, 235L, 223L),
counts = c(3L, 2L, 3L)), .Names = c("id", "feature", "counts"),
row.names = c(NA, -3L), class = "data.frame")
y <- structure(list(id = c(21L, 21L, 21L, 21L, 21L, 21L, 22L, 22L,
22L, 22L, 22L, 23L, 23L, 23L, 23L, 23L, 23L), feature = c(234L,
290L, 234L, 7802L, 3467L, 234L, 235L, 235L, 1234L, 236L, 134L,
9133L, 223L, 245L, 223L, 122L, 223L)), .Names = c("id", "feature"),
class = "data.frame", row.names = c(NA, -17L))
【讨论】:
感谢您的回答。但我一开始并不知道我需要找到的特征的位置。正如您在第二部分中提到的那样,它找到了第一个特征的出现。但我不知道该特征在“id-feature”数据框中的位置。我只知道要查找哪些功能存储在不同的数据框中。假设要查找的特征存储在x中,这个命令怎么写:DT[, .N, by = "id,feature"][, .SD[1], by = "id"] 我已经编辑了这个问题,通过指定 x 数据框中的内容以及最终输出应该是什么。我觉得很清楚。等待您的答复...... 您好,谢谢您的回答。我对R真的很陌生。你能推荐我吗,我可以在哪里学习编写这样的命令......? .N 和 .SD 参数对我来说是新的。 @ShreedharPawar,它们是“data.table”包的一部分,并记录在安装和加载包时可用的手册页和小插图中。 @ShreedharPawar,正如此处另一个答案所指出的那样,20GB CSV 不一定需要 R 中的 20GB 内存。【参考方案2】:我会为此推荐 data.table 包(fread
非常快!),然后设置一个循环,循环遍历一次读取块的文件并存储特征计数总和。这是我用于循环文件的函数的一些改编行,它可能无法按原样工作,但您可以了解该怎么做
require(data.table)
LineNu <- as.numeric(gsub(" .+","",system2("wc",paste("-l",your.file,sep=" "),stdout=TRUE, stderr=TRUE)))
DT <- fread(your.file,nrows=50000000,sep=",",header=TRUE)
KEEP.DT <- DT[,list("feature"=sum(length(feature))),by=id]
rm(DT) ; gc()
Starts <- c(seq(50000000,LineNu,by=50000000),LineNu)
for (i in 2:(length(Starts)-1))
cat(paste0("Filtering next 50000000 lines ", i, " of ",length(Starts)-1, " \n"))
DT <- fread(your.file,skip=Starts[i],nrows=ifelse(50000000*(i-1) < Starts[length(Starts)],50000000,(50000000*(i-1)) - Starts[length(Starts)]),sep=",",header=FALSE)
DT[,list("feature"=sum(length(feature))),by=id]
KEEP.DT <- rbind(KEEP.DT,DT)
rm(DT) ; gc()
您可能需要重做 DT[sum(length)] 部分,因为某些 id 可能会以不同的块读取。
【讨论】:
使用data.table
不需要循环。 fread
与大多数 by
处理一样快。
我认为需要循环,因为文件是 20Gb,他有 16Gb 的 RAM。
20GB CSV 并不一定意味着 R 内存中有 20GB 内存【参考方案3】:
你的例子:
apply(sign(table(y)), 1, sum)
21 22 23
4 4 2
【讨论】:
【参考方案4】:table() 怎么样?
> set.seed(5)
> ids <- sample(1:3, 12, TRUE)
> features <- sample(1:4, 12, TRUE)
> cbind(ids, features)
ids features
[1,] 1 2
[2,] 3 3
[3,] 3 2
[4,] 1 1
[5,] 1 2
[6,] 3 4
[7,] 2 3
[8,] 3 4
[9,] 3 4
[10,] 1 3
[11,] 1 1
[12,] 2 1
> table(ids, features)
features
ids 1 2 3 4
1 2 2 1 0
2 1 0 1 0
3 0 1 1 3
例如,特征 4 在 id 3 中出现 3 次。
编辑:您可以使用 as.data.frame() 来“展平”表格并获得:
> as.data.frame(table(ids, features))
ids features Freq
1 1 1 2
2 2 1 1
3 3 1 0
4 1 2 2
5 2 2 0
6 3 2 1
7 1 3 1
8 2 3 1
9 3 3 1
10 1 4 0
11 2 4 0
12 3 4 3
【讨论】:
我需要使用 feature_count 作为数据框进行进一步处理。 table() 只会给出一个表示。以上是关于以更快的方式计算 R 中列中不同 id 的特征的主要内容,如果未能解决你的问题,请参考以下文章