【问题标题】:In R, sample n rows from a df in which a certain column has non-NA values (sample conditionally)在 R 中,从 df 中采样 n 行,其中某一列具有非 NA 值(有条件地采样)
【发布时间】:2021-10-10 18:56:55
【问题描述】:

背景

这是一个玩具df

df <- data.frame(ID = c("a","b","c","d","e","f"), 
                gender = c("f","f","m","f","m","m"), 
                zip = c(48601,NA,29910,54220,NA,44663),stringsAsFactors=FALSE)

如您所见,NA 列中有几个 NA 值。

问题

我正在尝试从 df 中随机抽取 2 整行——但我希望它们是 zip 不为空的行。

我的尝试

此代码为我提供了一个基本(即非条件)随机样本:

df2 <- df[sample(nrow(df), 2), ]

当然,这只会让我实现目标的一半——很多时候它会在zip 中返回具有NA 值的行。此代码尝试添加条件:

df2 <- df[sample(nrow(df$zip != NA), 2), ]

我想我已经接近了,但这会产生错误invalid first argument

有什么想法吗?

【问题讨论】:

    标签: r dataframe random subset


    【解决方案1】:

    我们可以使用is.na

    tmp <- df[!is.na(df$zip),]
    > tmp[sample(nrow(tmp), 2),]
    

    【讨论】:

    • 谢谢!这行得通,而且它肯定会在紧要关头做,但我正在处理的真实数据集有大约 2 亿行(和大约 15 个列),我想知道制作第一个 tmp 是否会花费很多的时间。让我尝试运行它,看看我们是怎么做的。
    • @logjammin 如果它很大,为什么不使用data.tablelibrary(data.table);setDT(df)[!is.na(tmp)][sample(.N, 2)]
    • 我现在会尝试并报告。谢谢阿克伦。
    • 在真实数据集上运行最新代码时出现错误(` i 是无效类型(矩阵)), but thankfully your original answer actually works very well. My concerns about the speed of running tmp sample 也完全没有时间,我得到了我想要的新的df。非常感谢。
    • @logjammin 该错误似乎与数据集的类型有关。即data.frame vs matrix
    【解决方案2】:

    我们可以使用rownames + na.omit 对行进行采样

    > df[sample(rownames(na.omit(df["zip"])), 2),]
      ID gender   zip
    3  c      m 29910
    4  d      f 54220
    

    【讨论】:

    • na.omit 中我们能做到na.omit(df$zip) 吗?我不介意其他列是否有NA,只要zip 有。
    • @logjammin 好的,我明白了。请检查我的更新。
    【解决方案3】:

    这是complete.cases() 的基本 R 解决方案

    # define a logical vector to identify NA
    x <- complete.cases(df)
    
    # subset only not NA values
    df_no_na <- df[x,]
    
    # do the sample
    df_no_na[sample(nrow(df_no_na), 2),]
    

    输出:

      ID gender   zip
    3  c      m 29910
    6  f      m 44663
    

    【讨论】:

    • 这很棒,而且速度很快。谢谢。我将根据上面 akrun 的解决方案对其进行基准测试,看看谁在“真实”数据集上获胜,该数据集相当大(~200m x ~15)。
    • 这确实很棒。
    • 啊等一下,但假设在真实数据集中还有其他带有NA 的列——完成案例不会只选择每列都完整的行(即,任何地方都没有NA)?我不关心在其他列中有其他NA,只关心zip
    • 你可以做x &lt;- complete.cases(df[,3])。仅适用于第 3 列,例如zip.
    【解决方案4】:

    献给tidyverse 的爱好者...

    library("dplyr")
    df %>% 
      tidyr::drop_na() %>% 
      dplyr::slice_sample(n = 2)
    
    

    如果你关心的zip列中只有NA,那么:

    df %>% 
      tidyr::drop_na(zip) %>% 
      dplyr::slice_sample(n = 2)
    

    【讨论】:

      【解决方案5】:

      这里重要的是避免创建不必要的第二个数据框,其中 NA 值被丢弃。您可以使用另一个答案中给出的na.omit 的解决方案,但也可以使用which 返回要从中采样的有效行列表。例如:

      nsamp <- 23
      df[sample(which(!is.na(df$zip)), nsamp), ]
      

      这样做的好处是which 中的条件可以是您喜欢的任何内容,无论它是否涉及缺失值。例如,此版本将从邮政编码中以 336 开头的所有女性行中采样:

      df[sample(which(df$gender=='f' & grepl('^336', df$zip)), nsamp), ]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-05
        • 1970-01-01
        • 2017-11-26
        • 1970-01-01
        相关资源
        最近更新 更多