根据规则对用户进行群集或分组

时间:2017-10-12 09:02:37

标签: r data.table grouping

需要根据产品和群集的大小对数据进行群集。这是一个可重复的例子:

Output <-  fread('User_ID,Product,Cluster
      A,"P1",1
      B,"P1",1
      C,"P1",1
      D,"P1",2
      E,"P2",3
      F,"P2",3
      G,"P3",4
      H,"P3",4
      I,"P3",4
      J,"P3",5
      K,"P3",5
      L,"P3",5
      M,"P3",6')

群集的最大大小不能大于3.此外,每个群集只应包含一种类型的产品。 我正在寻找的输出是:

Var textbooks = [ ];

textbooks.push( javabook );

textbooks.push( vb6book );

console.log("Whole obj - -> ",textbooks)

3 个答案:

答案 0 :(得分:4)

这是一个data.table方法。

mydata[, cluster := as.integer(factor(paste(Product, (rowid(Product) - 1L) %/% 3)))]

我们的想法是将产品粘贴到产品rowid的输出中,该产品会单独计算每个产品。从此计数中减去1并使用%/%得到整数除法结果。将字符向量转换为一个因子,它将以字面顺序对数据进行排序,然后再为整数。

返回

mydata
    User_ID Product cluster
 1:       A      P1       1
 2:       B      P1       1
 3:       C      P1       1
 4:       D      P1       2
 5:       E      P2       3
 6:       F      P2       3
 7:       G      P3       4
 8:       H      P3       4
 9:       I      P3       4
10:       J      P3       5
11:       K      P3       5
12:       L      P3       5
13:       M      P3       6

效率的潜在改进是使用interaction代替paste / factor,如下所示:

mydata[, cluster := as.integer(interaction(Product, (rowid(Product) - 1L) %/% 3,
                                           lex.order=TRUE))]

返回的值仍然正确聚类,并且是有序的,但它们不直接遵循自然数序列。

mydata
    User_ID Product cluster
 1:       A      P1       1
 2:       B      P1       1
 3:       C      P1       1
 4:       D      P1       2
 5:       E      P2       4
 6:       F      P2       4
 7:       G      P3       7
 8:       H      P3       7
 9:       I      P3       7
10:       J      P3       8
11:       K      P3       8
12:       L      P3       8
13:       M      P3       9

答案 1 :(得分:1)

请试试这个。我希望这可以进一步优化:

test=mydata%>%group_by(Product)%>%mutate(count = n())%>%ungroup()
.GlobalEnv$counter = 0;

clust = ddply(.data = test,.variables = c('Product'),function(t){
      if(t$count[1]<=3){
          .GlobalEnv$counter=.GlobalEnv$counter+1;  
          Cluster = rep(.GlobalEnv$counter,t$count[1])
          t = cbind(t,Cluster)
      }else{
          .GlobalEnv$counter=.GlobalEnv$counter+1;
          factor=floor(t$count[1]/3);
          if(t$count[1]%%3==0){
                Cluster = rep(seq(.GlobalEnv$counter,.GlobalEnv$counter+(factor-1),by = 1),each=3)
                t = cbind(t,Cluster)
            }else{
                tempclust = rep(seq(.GlobalEnv$counter,.GlobalEnv$counter+(factor-1),by = 1),each=3)
                .GlobalEnv$counter = .GlobalEnv$counter+factor
                Cluster = c(tempclust,rep(.GlobalEnv$counter,each=(t$count[1]%%3)))
                t = cbind(t,Cluster)
            }
  }})
clust%>%select(Product,User_ID,Cluster)

#    Product User_ID Cluster
#1       P1       A       1
#2       P1       B       1
#3       P1       C       1
#4       P1       D       2
#5       P2       E       3
#6       P2       F       3
#7       P3       G       4
#8       P3       H       4
#9       P3       I       4
#10      P3       J       5
#11      P3       K       5
#12      P3       L       5
#13      P3       M       6

此逻辑可能仅适用于奇数编号的组长度,在这种情况下为3。

答案 2 :(得分:0)

这是另一种解决方案:

my_data_grp <- mydata %>%
  group_by(Product) %>%
  summarise(count= n())

my_data_grp$counter <- 1:nrow(my_data_grp)
mydata <- merge(mydata,my_data_grp,by = 'Product')
cnt=0
fin=data.frame()
for (i in 1:nrow(my_data_grp)){
  temp= mydata %>%
    filter(counter==my_data_grp$counter[i])
  #print(final_ProductGrp$cnt[i])
  temp$index = 1:nrow(temp)
  temp$quotient = ceiling(temp$index/3)+cnt
  cnt=max(temp$quotient)
  fin <- rbind(fin,temp)
}
View(fin)

提供所需的输出。