按组查找第一个/最后一个观察值?
我正试图找出小组的第一个/最后一个观察 。 我厌倦了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,])}}
首先,假设数据按Shopper
sorting,然后按升序排列,可以添加一个表示购买数量的列
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”而其他观测值保持不变,则可以使用ifelse
或replace
并使用“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只使用一个核心进行计算。