按组查找第一个/最后一个观察值?

我正试图找出小组第一个/最后一个观察 。 我厌倦了R和Excel(因为它在R中如此之慢,所以我尝试了卓越)。 Excel花了不到 秒钟 ,但R花了8分钟! 。 两者的代码逻辑几乎相同。

数据是关于购买水果面板数据 。 同一个购物者可以在不同的时间多次购买。 我有233000个观察。 数据就像(按购物者的第一天和第一天分类):

Day Shopper Choice 1 A apple 2 A apple 1 B Banana 1 C apple 2 C Banana 3 C apple 1 D berry 2 D berry 

我的代码为第一obseravtion。 我想通过指标“1”(一个新的列)标记组中的第一个观察值。

  for (i in 1:n) { ifelse (dt$shopper[i+1]==dt$shopper[i],newcol[i+1]<-0,newcol[i+1]<-1) } 

我的excel代码是:if(B2 <> B1,1,0)

我需要给予同一购物者的再购买matrix 。 定义回购:“第一购买”的回购是“第二购买”; 而“第二购买”的回购是“第三购买”。最后一次购买没有回购。 对不起,这听起来像是一个扭曲。 所以我的解决scheme是得到两个select科尔,并移动第二个上面的一行上面,所以我可以计算购物者/或聚合的repurchasematrix。所需的输出标签首先obs按组应该如下。 随着select的列和select2,我可以计算回购matrixnrow。

 Day Shopper Choice tagging choice 2 1 A apple 0 *apple* 2 A apple *apple* 0 1 B Banana 0 0 1 C apple 0 Banana 2 C Banana Banana apple 3 C apple apple 0 1 D berry 0 *berry* 2 D berry *berry* 0 

[ 更新 ]。 如果此用户只有一笔购买,则不会有任何回购。 如果购买是用户的最后购买,则不存在再购买。 所以在这种情况下,最终的回购matrix是可选的

  second inside bracket are the probability first apple banana berry apple 1 (0.5) 1 0 banana 1 0 (0) 0 berry 0 0 1 (1) 

以下是我如何计算标记第一次购买用户后的再购买matrix。 我是行(苹果,香蕉,浆果等)和j(苹果,香蕉,浆果等)是专栏。 [速度是好的,给我的回购matrix是40 * 40的事实,在标签和添加后续select列)

  for (i in 1:n){ for(j in 1:n){ repurchase_matrix[i,j]=nrow(dt[dt[,1]==i&dt[,2]==j,])}} 

首先,假设数据按Shoppersorting,然后按升序排列,可以添加一个表示购买数量的列

 df$Purchase <- unlist(with(df, tapply(Shopper, Shopper, seq_along))) df # Day Shopper Choice Purchase #1 1 A apple 1 #2 2 A apple 2 #3 1 B Banana 1 #4 1 C apple 1 #5 2 C Banana 2 #6 3 C apple 3 #7 1 D berry 1 #8 2 D berry 2 

然后将dataframe重新整形为“宽”格式

 df.w <- reshape(df[c('Shopper', 'Choice', 'Purchase')], idvar='Shopper', v.names='Choice', timevar='Purchase', direction='wide') df.w # Shopper Choice.1 Choice.2 Choice.3 #1 A apple apple <NA> #3 B Banana <NA> <NA> #4 C apple Banana apple #7 D berry berry <NA> 

最后你计算前两次购买的回购matrix

 with(df.w, prop.table(table(First=Choice.1, Second=Choice.2))) # Second #First apple Banana berry # apple 0.3333333 0.3333333 0.0000000 # Banana 0.0000000 0.0000000 0.0000000 # berry 0.0000000 0.0000000 0.3333333 

为了计算所有采购的回购matrix,从每两个连续采购的回购matrix开始

 repurchase <- lapply(seq(2, ncol(df.w) - 1), function(i) table(First=df.w[[i]], Second=df.w[[i + 1]])) repurchase <- simplify2array(repurchase) repurchase #, , 1 # # Second #First apple Banana berry # apple 1 1 0 # Banana 0 0 0 # berry 0 0 1 # #, , 2 # # Second #First apple Banana berry # apple 0 0 0 # Banana 1 0 0 # berry 0 0 0 

然后添加所有的matrix,以获得“总”回购matrix

 apply(repurchase, 1:2, sum) # Second #First apple Banana berry # apple 1 1 0 # Banana 1 0 0 # berry 0 0 1 

(绝对频率)

 prop.table(apply(repurchase, 1:2, sum)) # Second #First apple Banana berry # apple 0.25 0.25 0.00 # Banana 0.25 0.00 0.00 # berry 0.00 0.00 0.25 

(相对频率)

R ,我们可以使用dplyr 。 在“购物者”分组后,通过使用逻辑条件row_number() < 2创build第一个观察的“标记”列,并根据需要将逻辑转换为整数。

 library(dplyr) df1 %>% group_by(Shopper) %>% mutate(Flag = as.integer(row_number() < 2)) 

如果我们可以使用最小和最大“日”作为标识符,那么使用基于此的逻辑条件。

 df1 %>% group_by(Shopper) %>% mutate(Flag = as.integer(Day %in% range(Day))) 

或者使用data.table

 library(data.table) setDT(df1)[, Flag := as.integer(Day %in% range(Day)), by = Shopper] 

或者使用base R ,我们可以将之前的“购物者”与当前的“购物者”进行比较(假设数据集已经订购)

 i1 <- with(df1, Shopper[-1]!= Shopper[-nrow(df1)]) as.integer(c(TRUE, i1)|c(i1, TRUE)) #[1] 1 1 1 1 0 1 1 1 

所有这些方法应该比OP代码中的for循环更快。

更新

根据更新后的预期结果,如果我们需要用第一个观测值replace为“0”而其他观测值保持不变,则可以使用ifelsereplace并使用“tagging”的lead ,我们创build“tagChoice2”。

 df1 %>% group_by(Shopper) %>% mutate(tagging = ifelse(row_number()==1, "0", as.character(Choice)), tagChoice2 = lead(tagging, default = "0")) # Day Shopper Choice tagging tagChoice2 # <int> <chr> <chr> <chr> <chr> #1 1 A apple 0 apple #2 2 A apple apple 0 #3 1 B Banana 0 0 #4 1 C apple 0 Banana #5 2 C Banana Banana apple #6 3 C apple apple 0 #7 1 D berry 0 berry #8 2 D berry berry 0 

您可以尝试安装Microsoft R open作为您的默认R.就math计算而言,它比R base更快。 因为它使用更多的核心,而R.BASE只使用一个核心进行计算。