代码之家  ›  专栏  ›  技术社区  ›  cpage

变异前n行而不丢弃其他行

  •  1
  • cpage  · 技术社区  · 7 年前

    我有以下几点 data.frame 在下面。我想创建一个新列 w (重量)。 w 对于每个给定日期有n个最高回报的行业,应等于1/n,对于其他行业,应等于0。我可以 group_by(date) top_n(3, wt = return) 筛选顶级行业 mutate(w = 1/n) ,但我怎么能 mutate 不抛弃其他行业 = 0?

    structure(list(date = structure(c(16556, 16556, 16556, 16556, 
    16556, 16556, 16556, 16556, 16556, 16556, 16587, 16587, 16587, 
    16587, 16587, 16587, 16587, 16587, 16587, 16587, 16617, 16617, 
    16617, 16617, 16617, 16617, 16617, 16617, 16617, 16617), class = "Date"), 
        industry = c("Hlth", "Txtls", "BusEq", "Fin", "ElcEq", "Food", 
        "Beer", "Books", "Cnstr", "Carry", "Clths", "Txtls", "Fin", 
        "Games", "Cnstr", "Meals", "Hlth", "Hshld", "Telcm", "Rtail", 
        "Smoke", "Games", "Clths", "Rtail", "Servs", "Meals", "Food", 
        "Hlth", "Beer", "Trans"), return = c(4.89, 4.37, 4.02, 2.99, 
        2.91, 2.03, 2, 1.95, 1.86, 1.75, 4.17, 4.09, 1.33, 1.26, 
        0.42, 0.29, 0.08, -0.11, -0.45, -0.48, 9.59, 6, 5.97, 5.78, 
        5.3, 4.15, 4.04, 3.67, 3.51, 3.27)), row.names = c(NA, -30L
    ), class = c("tbl_df", "tbl", "data.frame"))
    
    # A tibble: 30 x 3
       date       industry return
       <date>     <chr>     <dbl>
     1 2015-05-01 Hlth       4.89
     2 2015-05-01 Txtls      4.37
     3 2015-05-01 BusEq      4.02
     4 2015-05-01 Fin        2.99
     5 2015-05-01 ElcEq      2.91
     6 2015-05-01 Food       2.03
     7 2015-05-01 Beer       2   
     8 2015-05-01 Books      1.95
     9 2015-05-01 Cnstr      1.86
    10 2015-05-01 Carry      1.75
    # ... with 20 more rows
    

    编辑 :您如何处理领带?假设第三名是平手。第三名的重量应该在第三名和第四名(假设只有两个并列)之间分配,重量为(1/n)/2。第一名和第二名的重量保持在1/n。

    编辑 :假设 n =3.前三名 A2 每个的值 A1 如果没有领带

    structure(list(A1 = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
        2L), .Label = c("A", "B"), class = "factor"), A2 = c(1, 3, 3, 
        4, 5, 6, 7, 8, 8)), row.names = c(NA, -9L), class = "data.frame")
    

    的输出 df 应该是:

    > df
      A1 A2  w
    1  A  1  0 
    2  A  3  0.1666
    3  A  3  0.1666 
    4  A  4  0.3333
    5  A  5  0.3333
    6  B  6  0
    7  B  7  0.3333
    8  B  8  0.3333
    9  B  8  0.3333
    
    2 回复  |  直到 7 年前
        1
  •  2
  •   Ronak Shah    7 年前

    date 然后 sort 这个 return return/n 否则为0。

    library(dplyr)
    n <- 3
    df %>%
      group_by(date) %>%
      mutate(w = ifelse(return %in% tail(sort(return), n), return/n, 0))
    
    
    # date       industry return     w
    #   <date>     <chr>     <dbl> <dbl>
    # 1 2015-05-01 Hlth       4.89  1.63
    # 2 2015-05-01 Txtls      4.37  1.46
    # 3 2015-05-01 BusEq      4.02  1.34
    # 4 2015-05-01 Fin        2.99  0   
    # 5 2015-05-01 ElcEq      2.91  0   
    # 6 2015-05-01 Food       2.03  0   
    # 7 2015-05-01 Beer       2     0   
    #....
    

    相同逻辑的基R等价,使用 ave

    ave(df$return, df$date, FUN = function(x) ifelse(x %in% tail(sort(x), n), x/n, 0))
    

    编辑

    正如在评论中提到的,在ties的情况下OP想要返回(1/n)/2或者除以我们拥有的ties数。

    为此,我创建了一个新的更容易的数据框架,它使人们更容易理解正在发生的事情。

    df <- data.frame(A1 = rep(c("A", "B"),c(5, 4)), A2 = 1:9)
    df$A2[2] <- 3
    

    如果我们使用它给出的当前代码

    df %>%
       group_by(A1) %>%
       mutate(w = ifelse(A2 %in% tail(sort(A2), n), A2/n, 0))
    
      # A tibble: 9 x 3
      # Groups:   A1 [2]
    #  A1       A2     w
    # <fct> <int> <dbl>
    #1 A         1  0   
    #2 A         3  1   
    #3 A         3  1   
    #4 A         4  1.33
    #5 A         5  1.67
    #6 B         6  0   
    #7 B         7  2.33
    #8 B         8  2.67
    #9 B         9  3   
    

    这不是我们想要的。为了避免这种情况,我们可以分组 A2 只为那些 w!=0 我们把它除以 A2级

    df %>%
      group_by(A1) %>%
      mutate(w = ifelse(A2 %in% tail(sort(A2), n), A2/n, 0)) %>%
      group_by(A2) %>%
      mutate(w1 = ifelse(w != 0, w/n(), w)) %>%
      ungroup()
    
    # A1       A2     w    w1
    #  <fct> <dbl> <dbl> <dbl>
    #1 A         1  0     0   
    #2 A         3  1     0.5 
    #3 A         3  1     0.5 
    #4 A         4  1.33  1.33
    #5 A         5  1.67  1.67
    #6 B         6  0     0   
    #7 B         7  2.33  2.33
    #8 B         8  2.67  2.67
    #9 B         9  3     3   
    

    另一个编辑

    结果我们只想分开 w 只为最后一组出席。此外,所有 w

    n <- 3
    
    temp_df <- df %>%
                group_by(A1) %>%
                top_n(n, A2)
    
    
     temp_df %>%
         arrange(A1, A2) %>%
         mutate(w = ifelse(A2 == A2[1], 
        (1 - (1/n * sum(A2 != A2[1])))/sum(A2 == A2[1]), 1/n)) %>%
         bind_rows(anti_join(df, temp_df) %>%
                          mutate(w = 0)
        ) %>%
         arrange(A1, A2)
    
    
    # A1       A2     w
    #  <fct> <dbl> <dbl>
    #1 A         1 0    
    #2 A         3 0.167
    #3 A         3 0.167
    #4 A         4 0.333
    #5 A         5 0.333
    #6 B         6 0    
    #7 B         7 0.333
    #8 B         8 0.333
    #9 B         8 0.333
    

    让我们尝试另一个变体,我们保持组的所有值相同。

    df1 = df
    df1$A2[6:9] <- 10
    
    
     temp_df <- df1 %>%
                 group_by(A1) %>%
                 top_n(n, A2)
    
    
      temp_df %>%
           arrange(A1, A2) %>%
           mutate(w = ifelse(A2 == A2[1], 
          (1 - (1/n * sum(A2 != A2[1])))/sum(A2 == A2[1]), 1/n)) %>%
           bind_rows(anti_join(df1, temp_df) %>%
                          mutate(w = 0)
           ) %>%
           arrange(A1, A2)
    
    
    #  A1       A2     w
    #  <fct> <dbl> <dbl>
    #1 A         1 0    
    #2 A         3 0.167
    #3 A         3 0.167
    #4 A         4 0.333
    #5 A         5 0.333
    #6 B        10 0.25 
    #7 B        10 0.25 
    #8 B        10 0.25 
    #9 B        10 0.25 
    

    逻辑是我们选择前三名 A2级 top_n . 使用 anti_join 我们得到所有不在前三名的行,并指定一个固定的权重 w 对于包含在前3个组中的行,我们得到最后一组行,并将权重分配给非最后一组后剩余的权重。

        2
  •  3
  •   akrun    7 年前

    我们可以创造一个条件 ifelse . 按“日期”分组后, arrange 数据集基于“date”和“return”按降序排列,然后通过创建条件来创建“w”,条件是 row_number() 小于“n”,则将“return”除以“n”,否则返回0

    n <- 3
    df1 %>%
       group_by(date) %>%
       arrange(date, -return) %>% 
       mutate(w = ifelse(row_number() <= n, return/n, 0))
    

    如果我们使用 top_n ,然后在筛选的数据集中创建列“w”,并与原始数据集联接

    df1 %>% 
      group_by(date) %>% 
      top_n(return, n = 3) %>% 
      mutate(w = return/n()) %>% 
      right_join(df1)  %>% 
      mutate(w = replace_na(w, 0))
    
    推荐文章