代码之家  ›  专栏  ›  技术社区  ›  S Das

基于列值的类分配

  •  1
  • S Das  · 技术社区  · 5 年前

    我有如下数据集:

    a <- structure(list(ID = c("a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"), 
                        E = c(1, 0, 0, 0,4, 4, 3, 0,1), 
                        W = c(0, 3, 2, 0, 3, 3, 3, 4,1), 
                        N = c(1, 0, 2, 0, 3, 4, 3, 7,1), 
                        S=c(0, 0, 0, 2, 1, 1, 3, 0,1)), 
                   .Names = c("ID", "E", "W", "N", "S"), row.names = c(NA, -9L), class = "data.frame")
    a
      ID E W N S
    1 a1 1 0 1 0
    2 a2 0 3 0 0
    3 a3 0 2 2 0
    4 a4 0 0 0 2
    5 a5 4 3 3 1
    6 a6 4 3 4 1
    7 a7 3 3 3 3
    8 a8 0 4 7 0
    9 a9 1 1 1 1
    

    我喜欢创造一个 class 列,将显示 column name 基于每行的最大数目。例如,ID为的第二行 a2 有一个 最大值 3用于 W 列。课程将是 W 最大值是3。当平局发生时 在最大值中 ,它将包括所有绑定的列名称。例如,对于第1行( ID=a1 双列 E 立柱 N 有一样 最大值 ,因此类将定义为 E-N ,最大值为1。

    我已经开始 melt 功能:

    library(reshape2)
    a1= melt(a, id=c("ID"))
    head(a1)
      ID variable value
    1 a1        E     1
    2 a2        E     0
    3 a3        E     0
    4 a4        E     0
    5 a5        E     4
    6 a6        E     4
    

    最终输出将是:

      ID   Class Max
    1 a1     E-N   1
    2 a2       W   3
    3 a3     W-N   2
    4 a4       S   2
    5 a5       E   4
    6 a6     E-N   4
    7 a7 E-W-N-S   3
    8 a8       N   7
    9 a9 E-W-N-S   1
    
    2 回复  |  直到 5 年前
        1
  •  2
  •   akrun    5 年前

    1) 一个选择是 gather 转换为“long”格式,按“id”分组, filter 行有 max “瓦尔” summarize 通过 paste 拿着钥匙 first “瓦尔”

    library(tidyverse)
    gather(a, key, val, -ID) %>% 
        group_by(ID) %>%
        filter(val == max(val)) %>% 
        summarise(Class = str_c(key, collapse="-"), Max = first(val))
    # A tibble: 9 x 3
    #  ID    Class     Max
    #  <chr> <chr>   <dbl>
    #1 a1    E-N         1
    #2 a2    W           3
    #3 a3    W-N         2
    #4 a4    S           2
    #5 a5    E           4
    #6 a6    E-N         4
    #7 a7    E-W-N-S     3
    #8 a8    N           7
    #9 a9    E-W-N-S     1
    

    2) 或其他选择 tidyverse 无需整形

    a %>% 
      mutate(out = select(., -1)  %>%
                      pmap(.,  ~ c(...) %>%
                       keep(. == max(.)) %>%
                      {tibble(Class = str_c(names(.), collapse='-'),
                              Max = first(.))})) %>%
      unnest
    #   ID E W N S   Class Max
    #1 a1 1 0 1 0     E-N   1
    #2 a2 0 3 0 0       W   3
    #3 a3 0 2 2 0     W-N   2
    #4 a4 0 0 0 2       S   2
    #5 a5 4 3 3 1       E   4
    #6 a6 4 3 4 1     E-N   4
    #7 a7 3 3 3 3 E-W-N-S   3
    #8 a8 0 4 7 0       N   7
    #9 a9 1 1 1 1 E-W-N-S   1
    

    3) 或使用 data.table

    library(data.table)
    melt(setDT(a), id.var = 'ID')[, {
         dat <- .SD[value == max(value)]
     .(Class = paste(dat$variable, collapse='-'), Max = dat$value[1])}, by = ID]
    

    注:这给出了操作的预期输出。


    4) 或使用 base R

    Max <- do.call(pmax, a[-1])
    Class <-  tapply(names(a)[-1][col(a[-1]) *NA^(a[-1] != Max)], 
         c(row(a[-1])), FUN = function(x)  paste(na.omit(x), collapse='-'))
    
        2
  •  3
  •   Ronak Shah    5 年前

    R基进近使用 apply 会找到 max 在每一行中查找相应的列名。

    a[c("max", "class")] <- t(apply(a[-1], 1, function(x) {
          val <- max(x)
          c(val, paste(names(a)[-1][x == val], collapse = "-"))
    }))
    
    a[c(1, 6, 7)]
    #  ID   max   class
    #1 a1     1     E-N
    #2 a2     3       W
    #3 a3     2     W-N
    #4 a4     2       S
    #5 a5     4       E
    #6 a6     4     E-N
    #7 a7     3 E-W-N-S
    #8 a8     7       N
    #9 a9     1 E-W-N-S
    

    您还可以使用 which (按照@tmfmnk的建议),替换中的最后一行 应用 调用

    c(val, paste(names(which(x == val)), collapse = "-"))