在R中识别只包含NA值的数据框行

12

我有一个包含34个序数和NA变量的,其中有15,000个观测值。 我正在进行市场细分研究的聚类,并需要删除仅包含NAs的行。在删除userID后,我收到了一个错误消息,要求在聚类之前省略2099行仅包含NAs的行。

我找到了一个链接可以删除所有NA值的行,但我需要确定这2099行中的哪些行具有全部NA值。这是有关删除中所有NA值的行的讨论链接: Remove Rows with NAs in data.frame

以下是六个变量的前五个观测值的示例:

> head(Store2df, n=5)
  RowNo      Age Gender HouseholdIncome MaritalStatus PresenceofChildren
1     1     <NA>   Male            <NA>          <NA>               <NA>
2     2    45-54 Female            <NA>          <NA>               <NA>
3     3     <NA>   <NA>            <NA>          <NA>               <NA>
4     4     <NA>   <NA>            <NA>          <NA>               <NA>
5     5    45-54 Female        75k-100k       Married                Yes
#Making a vector
> Vector1 <- Store2df$RowNo 
#Taking out RowNo column
> Store2df$RowNo <- NULL

编辑:我将结果放在一个对象中,但发现代码多了一列。在RStudio的环境中点击后,会创建一个名为row.names的额外列,并使用原始行名称标记每一行。删除了几千行数据,新列用旧行号标记了新行。但是当我查看新对象的头部时,我没有看到行标签。为什么row.names标签会显示在环境中,但不在查看头部时呢?

#Remove all rows with only NA values
> Store2df <- Store2[!!rowSums(!is.na(Store2)),]
#View head of store2df
> head(Store2df)
    Age Gender HouseholdIncome MaritalStatus PresenceofChildren
1  <NA>   Male            <NA>          <NA>               <NA>
2 45-54 Female            <NA>          <NA>               <NA>
5 45-54 Female        75k-100k       Married                Yes
6 25-34   Male        75k-100k       Married                 No
7 35-44 Female       125k-150k       Married                Yes
8 55-64   Male        75k-100k       Married                 No

编辑 2:我加入了行号/用户ID列以跟踪用户数量。为了执行删除所有NA的操作,我取出了第一列。现在我需要跟踪已删除的用户。我有一个包含2000多行所有值都是NA的列表,我不想手动创建索引来放入每一行。

问题:如何删除与缺失数据对应的电子邮件?

> #First six rows of the column RowNo
> head(Store2df$RowNo)
[1] 1 2 3 4 5 6

我希望在 Store2df 数据框中删除包含 RowNo 的 2099 行。以下是脚本,用于识别 Store2df 数据框中不包含 RowNo 的全部空行。

> which(rowSums(is.na(Store2df))==ncol(Store2df))

展示前6行,第3行和第4行已被删除。

> head(Store2df$RowNo)
[1] 1 2 5 6 7 8

我想完成以下4个步骤:

1)从Store2df data.frame中提取RowNo列并保存为单独的向量

2)删除Store2df data.frame中所有NA值的行

3)删除与Store2df data.frame相同的行,同时也从Store2new1 vector中删除

4)将vectordata.frame组合在一起,并使vectordata.frame匹配


那个链接是关于删除列的。你是不是想说这个链接:https://dev59.com/cG445IYBdhLWcg3wcJ2O?那么它没有解决你的问题在哪里呢? - David Robinson
@DavidRobinson 我犯了一个错误,发布了错误的链接,谢谢。我本来想发布那个链接,但是打开了太多标签页!那个链接会删除他们知道的NA行。我不想浏览所有15000行以确定哪些2099具有全部NA值。 - Scott Davis
你说的“they know of”是什么意思?该链接不需要提前知道哪个。话虽如此,那里的答案并没有完全回答你的问题,因为它们删除带有任何NA的行,而不仅仅是所有NA。 - David Robinson
@Scott Davis我无法弄清楚为什么它会创建row.names列。尝试了一些修改,但在RStudio全局环境中仍然有那个row.names。 - akrun
@akrun 我已经编辑了这篇文章。如果有什么需要澄清的,请告诉我。我想要减小向量 RowNo 的大小,以便与 data.frame Store2df 合并。RowNo 将会在 Store2df 中引用正确的信息。 - Scott Davis
显示剩余11条评论
2个回答

17
 which(rowSums(is.na(Store2))==ncol(Store2))
 #3 4 
 #3 4 

或者

 which(Reduce(`&`,as.data.frame(is.na(Store2))))
 #[1] 3 4

或者

 which(!rowSums(!is.na(Store2)))  
 #3 4 
 #3 4 

数据

 Store2 <- structure(list(Age = c(NA, "45-54", NA, NA, "45-54"), Gender = c("Male", 
 "Female", NA, NA, "Female"), HouseholdIncome = c(NA, NA, NA, 
  NA, "75k-100k"), MaritalStatus = c(NA, NA, NA, NA, "Married"), 
PresenceofChildren = c(NA, NA, NA, NA, "Yes"), HomeOwnerStatus = c(NA, 
NA, NA, NA, "Own"), HomeMarketValue = c(NA, NA, NA, NA, "150k-200k"
)), .Names = c("Age", "Gender", "HouseholdIncome", "MaritalStatus", 
"PresenceofChildren", "HomeOwnerStatus", "HomeMarketValue"), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5"))

更新

删除所有 NA 行。

  Store2[!!rowSums(!is.na(Store2)),]
  #   Age Gender HouseholdIncome MaritalStatus PresenceofChildren HomeOwnerStatus
  #1  <NA>   Male            <NA>          <NA>               <NA>            <NA>
  #2 45-54 Female            <NA>          <NA>               <NA>            <NA>
  #5 45-54 Female        75k-100k       Married                Yes             Own
   #HomeMarketValue
  #1            <NA>
  #2            <NA>
  #5       150k-200k
  • is.na(Store2) 返回一个逻辑索引,指示哪些元素缺失或为 NA
  • ! 可以对逻辑索引取反,即 TRUE 变成 FALSE,反之亦然
  • 上述代码的 rowSums 函数返回每行中非 NA 元素的总和

    rowSums(!is.na(Store2))
    #   1 2 3 4 5 
    #   1 2 0 0 7  # 3rd and 4th row have `0 non NA` values
  • ! 反转上述条件

  •     !rowSums(!is.na(Store2))
        # 1     2     3     4     5 
        #FALSE FALSE  TRUE  TRUE FALSE 
    
  • 我们想要删除那些 所有值都是NA 或者 0个非NA值 的行。所以再次使用 !

  •     !!rowSums(!is.na(Store2))
        #1     2     3     4     5 
        #TRUE  TRUE FALSE FALSE  TRUE 
    
  • 使用上述逻辑索引进行子集化操作

  • 更新2

    如果您有两个rowNo,即在删除NA行之前单独存储的行号和删除NA行后的第二个行号。

       RowNo1 <- 1:6
       RowNo2 <- c(1,2,5,6)
       RowNo1 %in% RowNo2
       #[1]  TRUE  TRUE FALSE FALSE  TRUE  TRUE
       RowNo1[RowNo1 %in% RowNo2]
       #[1] 1 2 5 6
    

    更新3

    根据您的新要求,让我再试一次:

        Store2 <- structure(list(RowNo = 1:5, Age = c(NA, "45-54", NA, NA, "45-54"
        ), Gender = c("Male", "Female", NA, NA, "Female"), HouseholdIncome = c(NA, 
        NA, NA, NA, "75k-100k"), MaritalStatus = c(NA, NA, NA, NA, "Married"
       ), PresenceofChildren = c(NA, NA, NA, NA, "Yes")), .Names = c("RowNo", 
       "Age", "Gender", "HouseholdIncome", "MaritalStatus", "PresenceofChildren"
       ), class = "data.frame", row.names = c("1", "2", "3", "4", "5"
       ))
    

    第一步

    RowNo保存为单独的向量(我不确定您需要这个的原因)

      Store2new1 <- Store2$RowNo
    

    第二步

    删除Store2数据框中所有值均为NA的行,并将其存储为名为Store2df的数据框

       Store2df <- Store2[!!rowSums(!is.na(Store2[,-1])),] #Here you already get the new dataset with `RowNo` column
    
       Store2df
       #RowNo   Age Gender HouseholdIncome MaritalStatus PresenceofChildren
       #1     1  <NA>   Male            <NA>          <NA>               <NA>
       #2     2 45-54 Female            <NA>          <NA>               <NA>
       #5     5 45-54 Female        75k-100k       Married                Yes
    

    第三步

    从 Store2new1 向量中删除与 Store2df 数据框相同的行。

       Store2new2 <- Store2new1[Store2new1 %in% Store2df$RowNo]
       Store2new1[Store2new1 %in% Store2df$RowNo]
       #[1] 1 2 5
    

    第四步

    我认为第四步或者第三步只有在你想删除更多行的情况下才需要,但这篇文章并没有明确说明。


    我将结果放在一个对象中,但发现另外一列显示了原始行。我们如何更改代码,以便它不插入额外的行? - Scott Davis
    @Scott Davis 你能告诉我df2是否为Store2以及你期望的输出吗? - akrun
    我打错字了,我仍然在引用这个表。 - Scott Davis
    我有另一个问题。假设我有一列包含所有的“UserID”。为了执行删除所有“NA”行的操作,我必须先删除用户ID。有些用户根本没有任何信息。在删除所有“NA”值的行之后,如何删除“UserID”?我不想将一千多行复制粘贴到索引函数中。 - Scott Davis
    @Scott Davis,据我所知,在删除所有“NA”的行之后,“Store2df”数据集中您得到了第1、2、5、6、7、8行。现在,我猜想您想要删除更多的行?例如,第1和2行在除第1列和第2列以外的所有列中都有缺失值。这有点不太清楚。您能展示一下预期结果吗?或者是您想要一系列的行号,而不是1、2、5、6等?如果是这种情况,则使用 row.names(Store2df) <- 1:nrow(Store2df) - akrun
    显示剩余7条评论

    4
    使用由@akrun提供的答案中发布的Store2示例数据
    which(apply(Store2, 1, function(x) all(is.na(x))))
    #3 4 
    #3 4 
    

    或者,类似于akrun的回答:
    which(rowSums(!is.na(Store2))==0)
    #3 4 
    #3 4 
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接