【问题标题】:Replace NA values in a column in dataframe based on probability of occurrence with non-NA values根据发生概率用非 NA 值替换数据框中列中的 NA 值
【发布时间】:2018-07-06 00:58:12
【问题描述】:

我必须在“桶”中随机填充一组“失败”值。

例如,

| Bucket | Failure | Id |
|--------|---------|----|
| B1     | F1      | 1  |
| B1     | F2      | 2  |
| B1     | F1      | 3  |
| B1     | null    | 4  |
| B1     | null    | 5  |
| B2     | F3      | 6  |
| B2     | F4      | 7  |
| B2     | null    | 8  |

在上表中,每个 Bucket 可以包含多条记录。其中一些记录将包含失败填充,但大多数不会。我的目标是根据桶内失败的比例随机分配失败。例如,对于组合 - {B1, F1} 与 B1 记录的比例(填充失败)是 2/3 对于 {B1, F2} B1 记录的比例(失败填充)是 1/3。

因此,B1 的 null 失败列 (Id=4,5) 的记录应该随机获得失败 F1 或 F2,但 F1 的比例为 2/3,F2 为 1/ 3.此逻辑需要应用于表中的所有存储桶。

我看到这是一件复杂的事情。我是一个 R 菜鸟,因此,任何代码示例都将不胜感激。

在这两者之间,我看到了这个问题。但是解决方案没有运行:Fill missing value based on probability of occurrence

查看示例代码:

test <- data.frame(
bucket = c(rep('B1', 5), rep('B2',3))
    , failure = c('F1', 'F2', 'F1', NA, NA, 'F3', 'F4', NA)
    , Id = seq(1:8)
)

test

sample_fill_na = function(x) {
    x_na = is.na(x)
    x[x_na] = sample(x[!x_na], size = sum(x_na), replace = TRUE)
    return(x)
}

test[, failure := sample_fill_na(failure), by = bucket]

【问题讨论】:

    标签: r random data.table


    【解决方案1】:

    这是一个可能的解决方案,我们可以在sample 函数中使用probs 参数,并使用table 函数创建权重(sample 将其转换为我们的概率)。

    希望这会有所帮助!

    library(data.table)
    test <- data.frame(bucket = c(rep('B1', 5), rep('B2',3)), failure = c('F1', 'F2', 'F1', NA, NA, 'F3', 'F4', NA), Id = seq(1:8))
    
    fillF <- function(x){
      y <- table(x)
      x[is.na(x)] <- sample(names(y),sum(is.na(x)),prob =y,replace=T)
      return(x)
    }
    
    setDT(test)[, failure := fillF(failure), by = bucket]
    

    输出:

       bucket failure Id
    1:     B1      F1  1
    2:     B1      F2  2
    3:     B1      F1  3
    4:     B1      F1  4
    5:     B1      F1  5
    6:     B2      F3  6
    7:     B2      F4  7
    8:     B2      F3  8
    

    我们可以很容易地用下面的代码检查比例:

    set.seed(1)
    for(i in 1:9){test=rbind(test,test)}
    setDT(test)[, failure := fillF(failure), by = bucket]
    table(test$failure)
    

    确实,比例看起来还不错:

      F1   F2   F3   F4 
    1705  855  749  787 
    

    编辑:如果您的数据中有空组,我们必须自己决定概率。有两个逻辑选项,始终填充默认值(例如F1),或者从所有选项中随机抽样。所以:

    library(data.table)
    test <- data.frame(bucket = c(rep('B1', 5), rep('B2',3),'B3'), failure = c('F1', 'F2', 'F1', NA, NA, 'F3', 'F4', NA,NA), Id = seq(1:9))
    
    fillF <- function(x){
      y <- table(x)
      if(sum(y)<1){y=c('F1'=1)} # always F1
      # if(sum(y)<1){y=y+1} # randomly sample from all possibilities
      x[is.na(x)] <- sample(names(y),sum(is.na(x)),prob =y,replace=T)
      return(x)
    }
    
    setDT(test)[, failure := fillF(failure), by = bucket]
    

    【讨论】:

    • 非常感谢这个解决方案。但是,我有一个问题/疑问。之前,我填充了 NA 值,如果我将失败列备份到不同的列中,该列的 NA 值也会被替换。例如,在我运行 setDT 函数之前,如果我在新列 test$failureNA
    • 那是因为列引用是一样的。试试test$failureNA &lt;- copy(test$failure) 而不是test$failureNA &lt;- test$failure
    • 再次感谢。但是,我收到一个错误:错误在 sample.int(length(x), size, replace, prob): too little positive probabilities in sample(names(y), sum(is. na(x)),概率 = y,替换 = T)
    • 那是因为你的数据有问题。有一个组没有 F 值,那么我们怎么知道如何填充缺失值呢?对于一种可能性,请参阅我的答案中的编辑(始终填写 F1)。希望对您有所帮助。
    • 我解决了概率太少的问题,但只要一个桶只有一个可能的失败,就会单独分配失败值。否则,解决方案是好的。 Florian,您能否调整您的解决方案,使故障不会被硬编码为 F1。我不知道该怎么做..
    【解决方案2】:

    这是一个潜在的解决方案,它基本上按照每个桶中的比例给出的概率对失败进行采样。

    test <- data.frame(
      bucket = c(rep('B1', 5), rep('B2',3))
      , failure = c('F1', 'F2', 'F1', NA, NA, 'F3', 'F4', NA)
      , Id = seq(1:8)
    )
    
    fillNA <- function(test) {
      uni <- unique(test$bucket)
      for (i in 1:length(uni)) {
        pos <- test$bucket == uni[i]
        tbl <- table(test[pos, 2])
        proportions <- tbl / sum(tbl)
        posNA <- pos & is.na(test[, 2])
        test[posNA, 2] <- sample(levels(test[, 2]), 
                                 sum(posNA),
                                 replace = TRUE,
                                 prob = proportions)
      }
      return(test)
    }
    fillNA(test)
    

    结果:

     bucket failure Id
    1     B1      F1  1
    2     B1      F2  2
    3     B1      F1  3
    4     B1      F1  4
    5     B1      F1  5
    6     B2      F3  6
    7     B2      F4  7
    8     B2      F4  8
    

    【讨论】:

      猜你喜欢
      • 2021-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-07
      • 2019-06-27
      • 2019-10-02
      • 2011-12-05
      相关资源
      最近更新 更多