【问题标题】:Replace values with a sample not equal to 0用不等于 0 的样本替换值
【发布时间】:2021-11-25 11:01:30
【问题描述】:

我想使用 sample 替换我的数据集中的 0 以随机选择要替换的列中的值。

我有这个示例数据集:

  Sepal.Length Sepal.Width Petal.Length Petal.Width species
1          0.0         3.5          0.0         0.2  setosa
2          4.9         3.0          0.0         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.0  setosa
5          5.0         0.0          0.0         0.0  setosa
6          0.0         0.0          0.0         0.4  setosa

我试过了:

ifelse(ir$Sepal.Width == 0, sample(ir$Sepal.Width != 0), ir$Sepal.Width)
[1] 3.5 3.0 3.2 3.1 0.0 0.0 3.4 1.0 2.9 1.0 3.7 1.0 3.0 3.0 4.0

零仍然存在。我尝试为所有列循环此代码,因为为每一列执行上面的代码太耗时,我已经尝试过:

lapply(ir[,-5], function(x)ifelse(ir[,1:4] == 0, sample(ir[,1:4]),ir[,1:4]))

但是,它会创建不必要的数据列,但仍保留零。

可重现的代码:

structure(list(Sepal.Length = c(0, 4.9, 4.7, 4.6, 5, 0, 4.6, 
5, 4.4, 0, 5.4, 4.8, 0, 0, 0), Sepal.Width = c(3.5, 3, 3.2, 3.1, 
0, 0, 3.4, 0, 2.9, 0, 3.7, 0, 3, 3, 4), Petal.Length = c(0, 0, 
1.3, 1.5, 0, 0, 1.4, 1.5, 1.4, 1.5, 0, 1.6, 1.4, 1.1, 1.2), Petal.Width = c(0.2, 
0.2, 0.2, 0, 0, 0.4, 0.3, 0.2, 0.2, 0, 0.2, 0, 0, 0, 0.2), species = structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("setosa", 
"versicolor", "virginica"), class = "factor")), row.names = c(NA, 
15L), class = "data.frame")

【问题讨论】:

    标签: r dataframe random replace data-manipulation


    【解决方案1】:

    这是一个简短的dplyr 解决方案:

    ir %>% 
      mutate(across(.cols = where(is.numeric), 
                  ~ replace(., . == 0, sample(.[. != 0], length(.[. == 0]), replace=T))))
    

    您可能需要也可能不需要replace=T,它允许重复采样元素。

    【讨论】:

      【解决方案2】:

      用向量中的随机非零值替换零的函数:

      f <- function(vec){
        
        ind <- vec == 0
        vec[ind] <- sample(vec[!ind], sum(ind), TRUE)
        
        vec
      }
      

      将函数f 应用于每个数字列:

      library(data.table)
      
      num_cols <- names(df)[as.vector(lapply(df, class)) == "numeric"]
      setDT(df)[, (num_cols) := lapply(.SD, f), .SD = num_cols]
      

      或使用基础R

      num_cols <- names(df)[as.vector(lapply(df, class)) == "numeric"]
      df[num_cols] <- lapply(df[num_cols], f)
      

      注意

      最好使用 Advanced R 一书中的 sample 函数:

      sample <- function(x, size = NULL, replace = FALSE, prob = NULL) {
        
        size <- size %||% length(x)
        x[sample.int(length(x), size, replace = replace, prob = prob)]
      }
      

      因为base::samplex 是长度为1 的数字时的行为。

      【讨论】:

        【解决方案3】:

        使用 data.table (library(data.table)):

        setDT(ir)
        ir[, Sepal.Width := 
               ifelse(Sepal.Width==0, 
                      sample(Sepal.Width[Sepal.Width!=0], .N, replace=TRUE), 
                      Sepal.Width), 
             by=species]
        

        您也可以通过添加by 来获取同一物种中的样本

        setDT(ir)
        ir[, Sepal.Width := 
               ifelse(Sepal.Width==0, 
                      sample(Sepal.Width[Sepal.Width!=0], .N, replace=TRUE), 
                      Sepal.Width), 
           by=species]
        

        为所有库获取此信息:

        ir[, c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width") := 
               lapply(.SD, function(x) {
                 ifelse(x==0, sample(x[x!=0], size=.N, replace=TRUE), x)}), 
           by=species]
        

        注意你的代码

        ifelse(ir$Sepal.Width == 0, sample(ir$Sepal.Width != 0), ir$Sepal.Width)
        

        是从 TRUEFALSE 的值中采样,因为您没有使用此逻辑运算 ir$Sepal.Width != 0 进行子集化 - 您需要

        ifelse(ir$Sepal.Width == 0, sample(ir$Sepal.Width[ir$Sepal.Width != 0]), ir$Sepal.Width)
        

        【讨论】:

          猜你喜欢
          • 2019-05-30
          • 1970-01-01
          • 2019-03-18
          • 2018-03-16
          • 2018-12-13
          • 2017-12-11
          • 2021-01-08
          • 2022-11-23
          相关资源
          最近更新 更多