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

使用R计数数据帧组中的类型数

  •  0
  • Lee  · 技术社区  · 1 年前

    我有这样的数据:

    data<-data.frame(is.on=c("FALSE","FALSE","FALSE","TRUE","FALSE","TRUE","FALSE","FALSE","TRUE","TRUE","TRUE","TRUE"),
                     dur=c(10,20,30,10,10,10,10,20,10,20,30,40),
                     dt=c(10,10,10,10,10,10,10,10,10,10,10,10),
                     block=c(2,2,2,3,4,5,6,6,7,7,7,7),
                     interval_block=c(1,1,1,2,2,2,3,3,3,4,4,4))
    

    现在我想 summary_data 基于 block 。 的行数 summary_data 是的类型数 interval_block 。 步骤1:

    # Step 1: Find the maximum number of types for block column within each interval_block
    max_types <- sapply(unique(data$interval_block), function(interval) {
      blocks <- unique(data[data$interval_block == interval, "block"])
      length(blocks)
    })
    max_num_types <- max(max_types) 
    

    对于 间隔_块 =1,有一种类型的块。(2) 对于 间隔_块 =2,有三种类型的块。(3、4和5) 对于 间隔_块 =3,有两种类型的块。(6和7) 对于 间隔_块 =4,有一种类型的块。(7) 因此,的最大类型数 每个内的列 间隔_块 是3。上面是计算这个数字的代码。根据这个数字,我想 dur_ 列。所以,在这种情况下,应该有 dur_1 , dur_2 dur_3

    第2步: 决定的值 dur_ 列。 对于 间隔_块 =1,有一种类型 。 我想填充 dur_1 然后离开 dur_2 dur_3 作为0。 #( =2以内 间隔_块 =1)=3。所以,我想填充 dur_1 为3乘以10=30。

    对于 间隔_块 =2,有三种类型 。 我想填充 dur_1 , dur_2 dur_3 。 #( =3以内 间隔_块 =2)=1, #( =4以内 间隔_块 =2)=1, #( =5以内 间隔_块 =2)=1。 所以,我想填补 dur_1 作为1乘以10=10, dur_2 为1乘以10=10并且 dur_3 为1乘以10=10。

    对于 间隔_块 =3,有两种类型 。 我想填充 dur_1 , dur_2 然后离开 dur_3 作为0。 #( =6以内 间隔_块 =3)=2, #( =7以内 间隔_块 =3)=1, 所以,我想填补 dur_1 作为2乘以10=20, dur_2 为1乘以10=10并且 dur_3 作为0。

    对于 间隔_块 =4,有一种类型 。 我想填充 dur_1 然后离开 dur_2 dur_3 作为0。 #( =7以内 间隔_块 =4)=3。 所以,我想填补 dur_1 作为3乘以10=10, dur_2 dur_3 作为0。

    我描述了很长时间的规则,但基本上都是关于计算 间隔_块 并乘以10。 我的预期输出应该是这样的:

    summary_data<-data.frame(dur_1=c(30,10,20,30),
                         dur_2=c(0,10,10,0),
                         dur_3=c(0,10,10,0),
                         interval_block=c(1,2,3,4))
    

    我不知道如何用R编码。

    请澄清。 第一排:有3个 =2(一种类型)。Sine one type,we only fill dur_1 其中3乘以10。 第二排,有1个 =3,1 =4和1 =5(三种类型)。由于有三种类型,我们填充 dur_1 , dur_2 dur_3 分别为1乘以10、1乘以10和1乘以10。

    第三排: 有2个 =6,1 =7(两种类型)。由于有两种类型,我们填充 dur_1 , dur_2 分别为2乘以10、1乘以10。

    1 回复  |  直到 1 年前
        1
  •  1
  •   I_O    1 年前

    利用{dplyr}和{tidyr},您可以执行以下操作:

    library(dplyr)
    library(tidyr)
    
    data |>
      group_by(interval_block) |>
      mutate(ID = row_number(),
             dur = block |> as.factor() |> as.integer(),
             dur = 1 + dur - min(dur),
             dur_names = paste0('dur_', dur),
             dur_values = 10 * dur
             ) |>
      group_by(interval_block, dur_names) |>
      summarise(dur_values = sum(dur_values)) |>
      pivot_wider(names_from = dur_names, values_from = dur_values) |>
      mutate(across(everything(), ~ ifelse(is.na(.x), 0, .x))) |>
      select(starts_with('dur'), interval_block)
    
    # A tibble: 4 x 4
    # Groups:   interval_block [4]
      dur_1 dur_2 dur_3 interval_block
      <dbl> <dbl> <dbl>          <dbl>
    1    30     0     0              1
    2    10    20    30              2
    3    20    20     0              3
    4    30     0     0              4
    

    编辑: 一个有点深奥的R基替代方案:

    data |>
      split(data$interval_block) |>
      Map(f = \(x) {
        max_blocks = with(data,  max(table(interval_block, block)))
        dur <- table(x$block)
        `[<-`(integer(max_blocks), seq_along(dur), 10 * dur)
      }) |>
      Reduce(f = rbind) |>
      cbind(unique(data$interval_block)) |>
      as.data.frame(row.names = FALSE) |>
      setNames(nm = c(paste0('dur_', 1:3), 'interval block'))
    

    '[<-' 用于从中获取的零填充 here

        2
  •  1
  •   Parfait    1 年前

    利用 base R,首先计算一个唯一的组块计数,然后聚合数据并通过清理将其重塑为最终格式:

    # ADD COLUMN FOR UNIQUE BLOCK GROUP NUM
    data <- within(
        data, {
            dur_num <- ave(
                block,
                interval_block, 
                FUN=\(x) as.integer(factor(x))
            )
        }
    ) 
    
    # AGGREGATE BY UNIQUE BLOCKS WITHIN INTERVAL BLOCK
    agg_df <- aggregate(
        dt ~ dur_num + interval_block,
        data,
        FUN = sum
    )
    
    # RESHAPE WIDE
    wide_df <- reshape(
        agg_df,
        idvar = "interval_block",
        timevar = "dur_num",
        v.names = "dt",
        direction = "wide",
        sep = "_"
    )
    
    # CLEAN UP
    wide_df[is.na(wide_df)] = 0
    
    row.names(wide_df) <- 1:nrow(wide_df)
    colnames(wide_df) <- gsub(
        "dt_", "dur_", colnames(wide_df), fixed=TRUE
    )
    
    
    wide_df
      interval_block dur_1 dur_2 dur_3
    1              1    30     0     0
    2              2    10    10    10
    3              3    20    10     0
    4              4    30     0     0
    

    Online Demo