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

时间:2016-07-09 05:00:46

标签: r excel

我正在尝试按群组找到第一个/最后一个观察结果。我厌倦了R和excel(因为它在R中很慢所以我尝试了excel)。 excel 花费少于一个 ,但 R 花了 8分钟!!! 。两者的代码逻辑几乎相同。

数据是关于购买水果的面板数据。同一购物者可以在不同的时间购买多次。 我有233,000个观察结果。数据就像(按天购物者排序第一天和第二天):

    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

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

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

我的excel代码是:           如果(B2&LT;&GT; B1,1,0)

在相同的购物者下,我需要重新购买矩阵。定义回购:“第一次购买”的回购是“第二次购买”;回购“第二次购买”是“第三次购买”最后一次购买没有回购。对不起,这听起来像是一个扭转者。 因此,我的解决方案是获得两个选择col并将第二个col移动到上面一行,这样我就可以通过购物者/或聚合来计算回购矩阵。标记首先按组分组的所需输出应如下所示。通过选择和选择2的列,我可以通过nrow计算回购矩阵。

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

[更新]。如果此用户只有一次购买,则无法重新购买。如果购买是用户的最后一次购买,则不会进行回购。因此,在这种情况下,最终的回购矩阵是

        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)

下面是我在标记首次购买用户后计算回购矩阵的方法。我是排(苹果,香蕉,浆果等)和j(苹果,香蕉,浆果等)是专栏。 [速度还可以,在标记并添加附加选择列后,我重新购买矩阵为40 * 40)

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

4 个答案:

答案 0 :(得分:4)

首先,假设数据按add_filter( 'woocommerce_package_rates', 'hide_shipping_when_free_is_available', 10, 2 ); function hide_shipping_when_free_is_available( $rates, $package ) { $cart_weight = WC()->cart->cart_contents_weight; // Cart total weight // Only modify rates if free_shipping is present if ( isset( $rates['free_shipping'] ) && $cart_weight > 80 ) { // Here your weight condition // To unset a single rate/method, do the following. This example unsets flat_rate shipping unset( $rates['flat_rate'] ); // To unset all methods except for free_shipping, do the following $free_shipping = $rates['free_shipping']; $rates = array(); $rates['free_shipping'] = $free_shipping; } return $rates; } 排序,然后按Shopper按升序排序,您可以添加一个表示购买编号的列

Day

然后将数据帧重新整形为&#34; wide&#34;格式与

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

最后,您计算前两次购买的回购矩阵

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>

要计算所有购买的回购矩阵,请从每两次连续购买的回购矩阵开始

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

然后添加所有矩阵以获得&#34;总计&#34;回购矩阵

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

(绝对频率)

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

(相对频率)

答案 1 :(得分:2)

R中,我们可以使用dplyr。在&#39; Shopper&#39;进行分组后,创建&#39;标记&#39;通过使用逻辑条件row_number() < 2进行首次观察的列,并在需要时将逻辑转换为整数。

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

如果我们可以使用最低和最高日期&#39;作为标识符,然后使用基于它的逻辑条件。

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,我们可以比较之前的购物者&#39;与现在的购物者&#39; (假设数据集已经订购)

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循环更快。

更新

根据更新的预期输出,如果我们需要用&#34; 0&#34;替换第一次观察如果其他人保持不变,可以使用ifelsereplace并使用lead标记&#39;,我们会创建&#39; tagChoice2&#39; ;

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

答案 2 :(得分:1)

我一直在寻找通过分组查找列的第一个和最后一个值的答案 在data.table中。在四处寻找并思考之后,就可以开始了。

要按组创建行顺序:

library(data.table)

DT <- data.table(col1 = rep(LETTERS[1:2], each = 4), col2 = c(3,12,5,56,6,678,233,70))
setorder(DT, col1, col2)
DT
   col1 col2
1:    A    3
2:    A    5
3:    A   12
4:    A   56
5:    B    6
6:    B   70
7:    B  233
8:    B  678

DT[, rank := order(col2), by = col1]
DT
   col1 col2 rank
1:    A    3    1
2:    A    5    2
3:    A   12    3
4:    A   56    4
5:    B    6    1
6:    B   70    2
7:    B  233    3
8:    B  678    4

要按组创建第一个和最后一个值:

DT[, first_val := col2[1], by = col2]
DT[, last_val := col2[.N], by = col1]
DT
   col1 col2 rank first_val last_val
1:    A    3    1         3       56
2:    A    5    2         3       56
3:    A   12    3         3       56
4:    A   56    4         3       56
5:    B    6    1         6      678
6:    B   70    2         6      678
7:    B  233    3         6      678
8:    B  678    4         6      678

答案 3 :(得分:0)

您可以尝试安装Microsoft R open作为默认R.在数学计算方面,它比R base快。因为它使用了更多内核,而R.BASE只使用一个内核来计算。