以更快的方式计算R中列中不同ID的要素

时间:2014-07-09 04:02:39

标签: r bigdata

我正在尝试在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的不同功能。我想计算在y中为id生成的另一个数据集x中列出的特定功能的次数。

数据集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循环中抛出一个错误,表示NA参数。请建议一个正确的方法来做到这一点。

4 个答案:

答案 0 :(得分:1)

我建议使用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可能会以不同的块读入。

答案 1 :(得分: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

如果您想要计算第一个“功能”,按“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))

答案 2 :(得分:0)

对于你的例子:

apply(sign(table(y)), 1, sum)
21 22 23 
 4  4  2 

答案 3 :(得分:0)

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()来&#34;展平&#34;表格得到:

> 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