假设该组包含至少一个非 NA 值,则删除组中具有 NA 的行

Remove rows with NA in a group, given the group contains at-least one non NA value

样本数据

df = structure(list(class = structure(c(4L, 1L, 1L, 3L, 2L), .Label = c("apple", 
"berry", "grape", "orange"), class = "factor"), value = c(NA, 
NA, 1, 1, NA)), .Names = c("class", "value"), row.names = c(NA, 
-5L), class = "data.frame")

看起来像

   class value
1 orange    NA
2  apple    NA
3  apple     1
4  grape     1
5  berry    NA

仅当该组具有另一个非 NA 值时,如何删除该组中具有 NA 的行

期望的输出

   class value
1 orange    NA
2  apple     1
3  grape     1
4  berry    NA

这可以通过使用子集和合并分三步完成。我对 data.table 方法感兴趣

我们可以使用 data.table。将 'data.frame' 转换为 'data.table' (setDT(df))。按 'class' 分组,我们使用 if/else 条件检查 'value' 和 .SD

子集中 'NA' 元素的出现情况
library(data.table)
setDT(df)[, if(any(!is.na(value))) .SD[!is.na(value)] else .SD , by = class]
#    class value
#1: orange    NA
#2:  apple     1
#3:  grape     1
#4:  berry    NA

或者我们可以通过稍微修改条件

将条件从any更改为all
setDT(df)[, if(all(is.na(value))) .SD else .SD[!is.na(value)], by = class]
#    class value
#1: orange    NA
#2:  apple     1
#3:  grape     1
#4:  berry    NA

或者我们获取行索引 (.I),然后对数据集进行子集化。

indx <- setDT(df)[, if(any(!is.na(value))) .I[!is.na(value)] else .I, class]$V1
df[indx]

您可以为所有带有 NA 的 类 创建一个临时变量,然后取出所有 NA 并将完全删除的任何 类 添加回来。

df<-setDT(df)
temp<-df[is.na(value),list(class=unique(class), value)]
df<-df[!is.na(value)]
df<-rbindlist(list(df, temp[!class %in% df[,class]]))
rm(temp)

尝试dplyr。它生成更简单的代码并且非常快,即使对于大型数据帧也是如此:

df %>%
    group_by(class) %>%
    filter(!(is.na(value) & sum(!is.na(value)) > 0)) %>%
    ungroup

末尾的取消分组位只是为了让您不会得到分组的数据帧(实际上是 dplyr::tbl)。

这是一种不同的 data.table 方法:

setkey(df,class)
df[!is.na(value)][J(unique(df$class))]

#     class value
# 1:  apple     1
# 2:  berry    NA
# 3:  grape     1
# 4: orange    NA

这要归功于默认操作 nomatch=NA。在控制台中输入 ?data.table 以获取详细信息。