首页 文章

根据另一列的值查找一列值的中值

提问于
浏览
1

我的朋友和我一直绞尽脑汁想知道如何从以下示例数据集中找到中位数:

A <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) #15 minute intervals
B <- c(4.1, 3.3, 11.7, 3.9, 2.9, 3.6, 4.8, 3.5, 5.0, 4.4, 4.9, 9.9, 8.5, 11.0, 14.0) #Blood glucose mmolperL
C <- c(NA, NA, 130, NA, NA, NA, NA, 115, NA, NA, NA, 120, NA, NA, NA) #Systolic Blood pressure
DF <- cbind(A,B,C)

从上述数据集中我们希望知道在收缩期(C列)的时间周围的中值血糖值(B列) . 问题在于与收缩压(130)的读数在同一行中的第一次血糖读数(11.7)与该时间点附近的其他读数完全不同 .

我们希望将这个11.7值附近的血糖数据点计算出来并计算中位数并将其分配给相应的血压 .

!!注意!!这是一个实验的一个示例数据集 . 在其他实验中,时间间隔不是很整齐,因此我们不能使用基于A列的常规子集标准 . 真正的数据帧也很多,更大,血压之间的行数更多读数 . 我简化了这个例子的数据框架 .

2 回答

  • 2

    虽然@Jaap为原始问题提供了很好的解决方案 . 我还在试图找到一种不使用 aggregate 的方法 .

    我想考虑 previousnextB 的当前读数( C 包含有效值)来计算 median .

    library(dplyr)
        DF %>%
          mutate(lag_B = lag(B), lead_B = lead(B)) %>%
          rowwise() %>%
          mutate(median_B = ifelse(is.na(C), NA_integer_,median(c(lag_B, B, lead_B))) ) %>%
          select(A, B, C, median_B)
    
    Results:
    # A tibble: 15 x 4
    #       A     B     C median_B
    #   <dbl> <dbl> <dbl>    <dbl>
    # 1  1.00  4.10    NA    NA   
    # 2  2.00  3.30    NA    NA   
    # 3  3.00 11.7    130     3.90
    # 4  4.00  3.90    NA    NA   
    # 5  5.00  2.90    NA    NA   
    # 6  6.00  3.60    NA    NA   
    # 7  7.00  4.80    NA    NA   
    # 8  8.00  3.50   115     4.80
    # 9  9.00  5.00    NA    NA   
    #10 10.0   4.40    NA    NA   
    #11 11.0   4.90    NA    NA   
    #12 12.0   9.90   120     8.50
    #13 13.0   8.50    NA    NA   
    #14 14.0  11.0     NA    NA   
    #15 15.0  14.0     NA    NA
    
  • 0

    可能的解决方案:

    w <- which(!is.na(DF$C))
    
    DF[w, 'B'] <- aggregate(B ~ rep(1:length(w), each = 3), DF[rep(w, each = 3) + c(-1,0,1),], median)$B
    

    这使:

    DF
    A B C.
    1 1 4.1 NA
    2 2 3.3 NA
    3 3 3.9 130
    4 4 3.9 NA
    5 5 2.9 NA
    6 6 3.6 NA
    7 7 4.8 NA
    8 8 4.8 115
    9 9 5.0 NA
    10 10 4.4 NA
    11 11 4.9 NA
    12 12 8.5 120
    13 13 8.5 NA
    14 14 11.0 NA
    15 15 14.0 NA

    这是做什么的:

    • w <- which(!is.na(DF$C)) 创建索引 w ,其中 C 不是NA .

    • 使用 aggregate ,您可以计算所需行的 median . 在这种情况下,我选择仅采用行本身以及 C 具有值的行之前和之后的行 .

    • DF[rep(w, each = 3) + c(-1,0,1),] 过滤 DF 只到所需的行

    • rep(1:length(w), each = 3)aggregate 创建分组矢量

    • 结果将分配回 B 中的rownumbers的 B 列 .


    您也可以将此逻辑与 data.table -package一起使用:

    # load the 'data.table'-package and convert 'DF' to a data.table with 'setDF'
    library(data.table)
    setDT(DF)
    
    # create two indexes:
    # 'i1' for when 'C' has a value
    # 'i2' which includes the previous and the next row for each value in 'i1'
    i1 <- DF[, .I[!is.na(C)]]
    i2 <- rep(i1, each = 3)
    
    # replace 'B' by reference with the median
    DF[i1, B := DF[i2 + -1:1, median(B), i2]$V1][]
    

    因为实际数据要大得多(如问题中所述),所以在更大的数据集上测试不同的解决方案是值得的 .

    首先,让我们创建一个大型数据集,模仿问题中的原始 DF

    DFbig <- DF[sample(nrow(DF), 1e7, TRUE),]
    setDT(DFbig)
    i <- DFbig[, .I[!is.na(C) & (!is.na(shift(C, type = 'lag')) | !is.na(shift(C, type = 'lead')))]]
    d <- c(2L,diff(i))
    i <- i[d > 1]
    DFbig2 <- DFbig[!i]
    

    基础R解决方案的时间安排:

    DFtest <- as.data.frame(DFbig2)
    
    system.time(
      {w <- which(!is.na(DFtest$C)); DFtest[w, 'B'] <- aggregate(B ~ rep(1:length(w), each = 3), DFtest[rep(w, each = 3) + c(-1,0,1),], median)$B}
    )
    

    用户系统已用完
    52.049 0.997 53.084

    dplyr 解决方案的时间安排:

    DFtest <- as.data.frame(DFbig2)
    
    system.time(
      DFtest %>% mutate(lag_B = lag(B), lead_B = lead(B)) %>% rowwise() %>% mutate(B = ifelse(is.na(C), NA_integer_, median(c(lag_B, B, lead_B))) ) %>% select(A, B, C)
    )
    

    用户系统已用完
    174.725 1.652 176.721

    data.table 解决方案的时间安排:

    DFtest <- copy(DFbig2)
    
    system.time(
      {i1 <- DFtest[, .I[!is.na(C)]]; i2 <- rep(i1, each = 3); DFtest[i1, B := DFtest[i2 + -1:1, median(B), i2]$V1][]}
    )
    

    用户系统已用完
    0.300 0.057 0.359

    从测试结果中可以清楚地看出: data.table -solution是最快的,其次是基本的R解决方案,而 dplyr -solution是迄今为止最慢的 .


    使用数据:

    DF <- data.frame(A = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
                     B = c(4.1, 3.3, 11.7, 3.9, 2.9, 3.6, 4.8, 3.5, 5.0, 4.4, 4.9, 9.9, 8.5, 11.0, 14.0),
                     C = c(NA, NA, 130, NA, NA, NA, NA, 115, NA, NA, NA, 120, NA, NA, NA))
    

相关问题