我已经为这个问题苦苦挣扎了一段时间了,所以我希望有人可以帮助我找到更省时的解决方案。
因此,我有一个ID的数据框,如下所示:

IDinsurer<-c(rep(11,3),rep(12,2),rep(11,2),rep(13,2),11)
ClaimFileNum<-c(rep('AA',3),rep('BB',2),rep('CC',2),rep('DD',2),'EE')
IDdriver<-c(rep(11,3),rep(12,2),rep(21,2),rep(13,2),11)
IDclaimant<-c(31,11,32,12,33,11,34,13,11,11)
IDclaimdriver<-c(41,11,32,12,11,21,34,13,12,11)
dt<-data.frame(ClaimFileNum,IDinsurer,IDdriver,IDclaimant,IDclaimdriver)

   ClaimFileNum IDinsurer IDdriver IDclaimant IDclaimdriver
1            AA        11       11         31            41
2            AA        11       11         11            11
3            AA        11       11         32            32
4            BB        12       12         12            12
5            BB        12       12         33            11
6            CC        11       21         11            21
7            CC        11       21         34            34
8            DD        13       13         13            13
9            DD        13       13         11            12
10           EE        11       11         11            11

我想做的是计算单个IDinsurer在其他角色(即不是保险人)中出现的不同索赔文件(ClaimFileNum)的数量。因此,对于每个IDinsurer,我只希望索要索赔文件的数量,他的ID出现在IDdriver,IDclaimant或IDclaimdriver中,而同时他又不是给定索赔文件的IDinsurer。例如,IDinsurer == 11与所有ClaimFileNums一起出现,但是仅在“BB”和“DD”上他不是IDinsurer,这意味着我希望我的程序返回2。
所以这就是我希望我的最终数据框看起来像这样的样子:
   ClaimFileNum IDinsurer IDdriver IDclaimant IDclaimdriver N
1            AA        11       11         31            41 2
2            AA        11       11         11            11 2
3            AA        11       11         32            32 2
4            BB        12       12         12            12 1
5            BB        12       12         33            11 1
6            CC        11       21         11            21 2
7            CC        11       21         34            34 2
8            DD        13       13         13            13 0
9            DD        13       13         11            12 0
10           AA        11       11         11            11 2

到目前为止,这是我能想到的:

1)
对于其他三个角色(IDdriver,IDclaimant,IDclaimdriver)中的每一个,我分别计算了一个新的列,其中包含一些数字,这些数字揭示了特定ID仅出现在该角色中的索赔文件数量,但不包括索赔文件,保险人也是保险人(但是,对于IDclaimdriver,更有意义的是排除ID匹配IDclaimant或IDdriver的情况)。这是IDdriver计数的代码:
count.duplicates <- function(dt){                                 #removing duplicated columns and adding a column with the frequency of duplications
  x <- do.call('paste', c(dt[,c("ClaimFileNum","IDdriver")], sep = '\r'))
  ox <- order(x)
  rl <- rle(x[ox])
  cbind(dt[ox[cumsum(rl$lengths)],,drop=FALSE],count = rl$lengths)

}
dt<-count.duplicates(dt)
dt<-data.table(dt)
dt[,same:=ifelse(dt$IDinsurer==dt$IDdriver,0,1)]
dt[,N_IDdriver:=sum(same,na.rm = T),by=list(IDdriver)]
dt[,same:=NULL]

setorder(dt,ClaimFileNum)
dt<-expandRows(dt,"count")
dt<-as.data.frame(dt)

这是我的示例在所有三个计数之后的输出:
       ClaimFileNum IDinsurer IDdriver IDclaimant IDclaimdriver N_IDdriver N_IDclaimant N_IDclaimdriver
1            AA        11       11         31            41          0            1               1
2            AA        11       11         11            11          0            1               1
3            AA        11       11         32            32          0            1               0
4            BB        12       12         12            12          0            0               1
5            BB        12       12         33            11          0            1               1
6            CC        11       21         11            21          1            1               0
7            CC        11       21         34            34          1            1               0
8            DD        13       13         13            13          0            0               0
9            DD        13       13         11            12          0            1               1
10           EE        11       11         11            11          0            1               1

2)现在,我首先在整个IDinsurer列上使用了for循环,以使用匹配功能检查insurerID [i]是否出现在其他三个角色ID中。如果找到匹配项,我只是将相应N_列中的计数添加到总计数中。
这是我的for循环:
total<-length(dt$IDinsurer)
for(i in 1:total) {
  j<-match(dt$IDinsurer[i],dt$IDdriver,nomatch=0);
  k<-match(dt$IDinsurer[i],dt$IDclaimant,nomatch=0);
  l<-match(dt$IDinsurer[i],dt$IDclaimdriver,nomatch=0);
  dt$N[i]<-ifelse(j==0,0,N_IDdriver[j])+ifelse(k==0,0,N_IDclaimant[k])+ifelse(l==0,0,N_IDclaimdriver[l]);
}

现在,尽管这种方法为我提供了我需要的所有信息,但令人遗憾的是,它非常缓慢,特别是在具有超过200万个案例的数据集(如我将要使用的案例)上。我敢肯定,必须有一个更优雅的解决方案,并且我一直在尝试找出如何使用一些更有效的工具(例如data.table)来做到这一点,但我只是无法掌握它。

编辑:我决定尝试在示例中回答我的问题的两个答案,并将其与我的尝试进行比较,因此这是计算时间:
Thom Quinn的for循环:0.15秒,
我的for循环:0.25秒,
bounyball的方法:0.35秒。

在104.2万行数据集上使用我的循环花了不到10个小时。

最佳答案

众所周知,匹配很慢,在这种情况下不需要。实际上,您已经用英语解决了问题,您只需要将其翻译成计算机术语即可!

因此,对于每个IDinsurer,我只希望索取索赔文件的数量,他的ID出现在IDdriver,IDclaimant或IDclaimdriver中,而同时他不是给定索赔文件的IDinsurer

所以,让我们做到这一点。用伪代码:

for each unique IDinsurer:
  count when IDdriver OR IDclaimant OR IDclaimdriver AND NOT IDinsurer

在R中,这是:
for(i in unique(dt$IDinsurer)){
  index <- dt$IDinsurer != i & (dt$IDdriver == i | dt$IDclaimant == i | dt$IDclaimdriver == i)
  dt[dt$IDinsurer == i, "N"] <- sum(index)
}

关于r - R-数据框的一列中的值在其他列中出现多少次? (最好不使用for循环),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41229105/

10-12 17:05