如何在R中处理多种缺失情况?

19

许多调查都有不同种类的缺失值代码,比如,代码手册可能会显示:

0-99 数据

-1 未提问

-5 不知道

-7 拒绝回答

-9 未参与模块

Stata具有处理这些多种缺失的美妙功能,它允许您将一个通用的“.”分配给缺失数据,但是也允许使用更具体的缺失类型(.a,.b,.c,...,.z)。所有查看缺失的命令都报告了所有指定的缺失条目的答案,但是您以后也可以区分各种缺失类型。当您认为拒绝回答对补全策略具有不同的影响时,这特别有帮助。

我从未在R中遇到过这样的功能,但我真的很想拥有这种能力。是否有标记几种不同类型NA的方法?我可以想象创建更多的数据(长度为nrow(my.data.frame)的向量,其中包含不同类型的缺失,或者更紧凑的索引,指示哪些行具有哪些类型的缺失),但这似乎非常笨拙。

6个回答

12

我知道您想要什么,但在R中没有实现这个功能。我不知道是否有已经实现了这个功能的包,但是自己编写也不难。

一个可行的方法是将包含代码的数据框添加到属性中。为了防止整个数据框被重复并节省空间,我会在该数据框中添加索引,而不是重新构建完整的数据框。

例如:

NACode <- function(x,code){
    Df <- sapply(x,function(i){
        i[i %in% code] <- NA
        i
    })

    id <- which(is.na(Df))
    rowid <- id %% nrow(x)
    colid <- id %/% nrow(x) + 1
    NAdf <- data.frame(
        id,rowid,colid,
        value = as.matrix(x)[id]
    )
    Df <- as.data.frame(Df)
    attr(Df,"NAcode") <- NAdf
    Df
}

这允许做到以下几点:
> Df <- data.frame(A = 1:10,B=c(1:5,-1,-2,-3,9,10) )
> code <- list("Missing"=-1,"Not Answered"=-2,"Don't know"=-3)
> DfwithNA <- NACode(Df,code)
> str(DfwithNA)
'data.frame':   10 obs. of  2 variables:
 $ A: num  1 2 3 4 5 6 7 8 9 10
 $ B: num  1 2 3 4 5 NA NA NA 9 10
 - attr(*, "NAcode")='data.frame':      3 obs. of  4 variables:
  ..$ id   : int  16 17 18
  ..$ rowid: int  6 7 8
  ..$ colid: num  2 2 2
  ..$ value: num  -1 -2 -3

该函数还可以调整以添加一个额外的属性,为不同的值提供标签。详见此问题。您可以通过以下方式进行反转换:

ChangeNAToCode <- function(x,code){
    NAval <- attr(x,"NAcode")
    for(i in which(NAval$value %in% code))
        x[NAval$rowid[i],NAval$colid[i]] <- NAval$value[i]

    x
}

> Dfback <- ChangeNAToCode(DfwithNA,c(-2,-3))
> str(Dfback)
'data.frame':   10 obs. of  2 variables:
 $ A: num  1 2 3 4 5 6 7 8 9 10
 $ B: num  1 2 3 4 5 NA -2 -3 9 10
 - attr(*, "NAcode")='data.frame':      3 obs. of  4 variables:
  ..$ id   : int  16 17 18
  ..$ rowid: int  6 7 8
  ..$ colid: num  2 2 2
  ..$ value: num  -1 -2 -3

这样可以只更改您想要的代码,如果有必要的话。当没有参数时,该函数可以适应返回所有代码。可以构建类似的函数来基于代码提取数据,我猜你自己可以想出那个。

但简单来说:使用属性和索引可能是一种不错的方法。


6
你应该抽出一些空闲时间,写一个程序包!=) - aL3xa
这很棒...自三月以来有关于这个话题的任何新闻吗? - Matt Bannert
我有一个小备注:当你开始编写你的NAs时,很可能已经有一种NA是NA(例如由于读取数据过程)。因此,如果code列表可以接受NAs而不仅仅是负整数和正整数,那将会很好。 - Matt Bannert
1
@ran2 关于这个话题还没有任何消息,但是一旦我弄清楚数据表,我可能会将其打包。这可能是那个扩展的一个不错的补充。 - Joris Meys
基于属性的方法唯一让人烦恼的是,许多命令会剥离属性,因此您需要付出一些努力来保留它们。 - Ari B. Friedman
显示剩余2条评论

6
最明显的方法似乎是使用两个向量:
- 向量1:一个数据向量,其中所有缺失值都用NA表示。例如,c(2, 50, NA, NA) - 向量2:一个因子向量,表示数据类型。例如,factor(c(1, 1, -1, -7)),其中因子1表示正确回答的问题。
有了这种结构,您将获得很大的灵活性,因为所有标准的na.rm参数仍适用于数据向量,但您可以使用更复杂的概念与因子向量一起使用。
@gsk3的问题更新如下:
- 数据存储将大幅增加:数据存储将翻倍。然而,如果数据大小加倍会带来实际问题,那么考虑其他策略可能是值得的。 - 程序不会自动处理它。这是个奇怪的评论。一些函数默认情况下以明智的方式处理NAs。但是,您想要以不同的方式处理NAs,这意味着您必须采取特定的措施。如果您只想分析“未询问问题”的数据,则只需使用数据帧子集。 - 现在,每次您想要概念上操作一个变量时,都必须同时操作两个向量。我想象中是两个向量的数据框架。我将根据第二个向量对数据框架进行子集。 - 没有标准实现,因此我的解决方案可能与其他人的不同。是的。但是,如果现成的包不能满足您的需求,那么(几乎)根据定义,您想要做某些不同的事情。
我应该说明,我从未分析过调查数据(尽管我已经分析过大型生物数据集)。我的答案以上看起来相当保守,但这并不是我的意图。我认为你的问题是一个好问题,我对其他答案感兴趣。

这肯定会起作用,但我看到了三个问题:1)数据存储需求显著增加(在具有数百个变量的调查中,这是非微不足道的),2)程序无法自动处理它(现在您必须每次想要概念化操作变量时将两个向量一起操作),3)没有标准实现,因此我的解决方案可能与其他人不同。可能值得编写一个新类,其中包含矢量和索引,但然后每个有趣的函数都必须具有相应的方法。 - Ari B. Friedman
感谢您的更新。我已经将其设想为一个大型数据框,并且数据框无法存储其他数据框。因此,如果不使用列表来保存变量的数据框,则很难实现。我将尝试在今天晚些时候给出更清晰的说明。 - Ari B. Friedman
1
@cgillespie:如果您使用稀疏向量或矩阵,则无需显著增加存储空间。 - Iterator

4
这不仅仅是一个“技术”问题。您需要对缺失值分析和插补有深入的统计背景。其中一种解决方案需要使用R和ggobi进行操作。您可以将极端负值分配给几种NA类型(将NA放入边距),并手动进行一些诊断。您应该记住有三种NA类型:
- MCAR - 完全随机缺失,其中P(missing | observed,unobserved)= P(missing) - MAR - 随机缺失,其中P(missing | observed,unobserved)= P(missing | observed) - MNAR - 非随机缺失(或不可忽略),其中P(missing | observed,unobserved)无法以任何方式量化。
在我看来,这个问题更适合CrossValidated
但是这里有一个来自SO的链接,您可能会发现它有用: 在R中处理缺失/不完整数据--是否有函数可以屏蔽而不是删除NAs?

1
我认为适当处理分析中的值涉及对缺失进行妥善核算,就像鲁宾所说的那样。在不同的研究中,我以不同的方式进行处理(例如多重插补或更多的临时解决方案),但它们都始于确认存在不同类型的缺失。我的问题是关于在数据集内跟踪这些不同类型的缺失的技术方面。 - Ari B. Friedman
在这种情况下,您根本不应该使用 NA - 就像 @Ralph 建议的那样。 - aL3xa
@aL3xa:但正如我在Ralph的建议中所指出的,NA具有一些不错的特性,它可以避免您意外忽略缺失的数据。 - Ari B. Friedman
好的,像@Joris建议的那样将attr添加到您的数据中是最终解决方案(尽管它仍然是一种解决方法)...我的回答真是无用啊!=) - aL3xa
我在编写代码的同时一直在查看我的数据,因此我永远不会无意中忽略它。 在排除错误后,我认为最好转向“真正的NA”,因为您可能(并且很可能)正在处理以前从未见过的数据,其中包含您需要捕获的“新”的缺失值。 - Ralph Winters
显示剩余2条评论

4
你可以完全不使用NA,而直接使用编码值。你还可以将它们合并为一个全局缺失值。我通常喜欢在没有NA的情况下进行编码,因为NA可能会在编码时出现问题,我希望能够控制分析中确切的内容。我也曾经使用字符串“NA”来表示NA,这通常会使事情更容易些。
-Ralph Winters

这个可以运行。然而,通常我更喜欢重新编码为NA,这样当我没有正确处理缺失数据时,分析就会失败。我发现当我将缺失数据存储为正常数据时,很容易犯错误。 - Ari B. Friedman

2

我通常将它们用作值,正如Ralph已经建议的那样,因为缺失值的类型似乎是数据,但在一两个场合,我主要想用它来进行文档记录,所以我已经在值上使用了一个属性,例如:

> a <- NA
> attr(a, 'na.type') <- -1
> print(a)
[1] NA
attr(,"na.type")
[1] -1

那样我的分析就会很干净,但我仍然保留文档。 但正如我所说:通常我会保留值。
艾伦。

1

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