【问题标题】:using ggpairs with NA-continaing data使用带有 NA 连续数据的 ggpairs
【发布时间】:2012-10-17 03:12:53
【问题描述】:

GGally 包中的ggpairs 似乎非常有用,但是当数据集中的任何位置出现NA 时,它似乎会失败:

#require(GGally)
data(tips, package="reshape")
pm <- ggpairs(tips[,1:3]) #works just fine

#introduce NA
tips[1,1] <- NA
ggpairs(tips[,1:3])
> Error in if (lims[1] > lims[2]) { : missing value where TRUE/FALSE needed

我没有看到任何处理 NA 值的文档,并且像 ggpairs(tips[,1:3], na.rm=TRUE) 这样的解决方案(不出所料)不会更改错误消息。

我有一个数据集,其中可能有 10% 的值是 NA,随机分布在整个数据集中。因此na.omit(myDataSet) 将删除大部分数据。有没有办法解决这个问题?

【问题讨论】:

  • 在 GGRally 中没有处理 NA 值的默认方法,至少我发现了这一点。我过去所做的只是将 NA 值替换为 0。这对于您拥有的数据集是否可行?
  • 不幸的是,这并不准确。我的 NA 通常是由于样本丢失/错误造成的,真实值不太可能为 0。

标签: r ggplot2


【解决方案1】:

GGally 的一些函数如ggparcoord() 支持通过missing=[exclude,mean,median,min10,random] 参数处理NA。但不幸的是,ggpairs() 并非如此。

您可以做的是用对您期望的数据的良好估计替换 NA,ggpair() 会自动为您完成。有很好的解决方案,比如用row meanszerosmedian 甚至closest point 替换它们(注意最近句子中的4个超链接!)。

【讨论】:

  • 我认为在缺少真实数据的地方发明数据点是非常危险的。您提到的技术在 R 中很容易 - 当替换的数量相对于观察总数而言很小时,我们可能能够摆脱它们 - 但是当替换的数量变得相当大时,就像在我的数据集中一样,你提到的技术相当于数据制造。
  • @DrewSteen 那么您认为 ggpairs() 在 NA 的最佳选择中会做什么?它可以想象应该填充的真正价值吗?没有选择,只能将 NA 连同相关数据一起删除,或者巧妙地用一些不会改变结果的估计来替换它们。
  • 是的,我希望它删除 NA 和成对的数据点,但要在不包括 NA 的图中保留来自同一数据框行的所有数据。因此,给定行或列中的散点图可能包含不同数量的数据点。相反,它只是抛出一条错误消息。
  • 但我的原始数据中确实有零!
  • 我真的很抗拒将假数据插入我的数据集中。在科学领域,编造数据(即使你很清楚这样做)确实非常不合适。
【解决方案2】:

我会用我自己可怕的解决方法来尝试一下,因为我认为这需要刺激。我同意 OP 的观点,即基于统计假设或选择的 hack 填充数据对于探索性分析来说是一个糟糕的主意,而且我认为一旦你忘记它是如何工作的(对我来说大约五天)并且需要调整,它肯定会失败它是为了别的。

免责声明

这是一种糟糕的做事方式,我讨厌它。它很有用,因为当你有一个系统的 NA 来源来自高维数据集的稀疏采样之类的东西时,可能 OP 有。

示例

假设您有一些非常大的数据集的一小部分,使您的某些列稀疏表示:

|  Sample (0:350)|  Channel(1:118)|  Trial(1:10)|     Voltage|Class  (1:2)|  Subject (1:3)|
|---------------:|---------------:|------------:|-----------:|:-----------|--------------:|
|               1|               1|            1|  0.17142245|1           |              1|
|               2|               2|            2|  0.27733185|2           |              2|
|               3|               1|            3|  0.33203066|1           |              3|
|               4|               2|            1|  0.09483775|2           |              1|
|               5|               1|            2|  0.79609409|1           |              2|
|               6|               2|            3|  0.85227987|2           |              3|
|               7|               1|            1|  0.52804960|1           |              1|
|               8|               2|            2|  0.50156096|2           |              2|
|               9|               1|            3|  0.30680522|1           |              3|
|              10|               2|            1|  0.11250801|2           |              1|

require(data.table) # needs the latest rForge version of data.table for dcast
sample.table <- data.table(Sample = seq_len(10), Channel = rep(1:2,length.out=10),
                           Trial = rep(1:3, length.out=10), Voltage = runif(10), 
                           Class = as.factor(rep(1:2,length.out=10)),
                           Subject = rep(1:3, length.out=10))

这个例子很糟糕,但假设列是从它们更大的子集中均匀采样的。

假设您想将所有通道的数据转换为宽格式以使用ggpairs 进行绘图。现在,规范的 dcast 回到宽格式将无法使用 id 列或其他方式,因为列范围被稀疏(并且永远不会完全)表示:

wide.table <- dcast.data.table(sample.table, Sample ~ Channel,
                                   value.var="Voltage",
                                   drop=TRUE)

> wide.table
        Sample         1          2
     1:      1 0.1714224         NA
     2:      2        NA 0.27733185
     3:      3 0.3320307         NA
     4:      4        NA 0.09483775
     5:      5 0.7960941         NA
     6:      6        NA 0.85227987
     7:      7 0.5280496         NA
     8:      8        NA 0.50156096
     9:      9 0.3068052         NA
    10:     10        NA 0.11250801

在这种情况下,很明显id 列会起作用,因为它是一个玩具示例 (sample.table[,index:=seq_len(nrow(sample.table)/2)]),但在巨大 data.table 的微小统一样本的情况下,基本上不可能找到 @ 的序列当应用于公式参数时,987654328@ 值将贯穿数据中的每个漏洞。这个组合会起作用:

setkey(sample.table,Class)

我们最后需要这个来确保顺序是固定的。

chan.split <- split(sample.table,sample.table$Channel)

这将为您提供每个唯一频道的 data.frames 列表。

cut.fringes <- min(sapply(chan.split,function(x) nrow(x)))
chan.dt <- cbind(lapply(chan.split, function(x){
  x[1:cut.fringes,]$Voltage}))

必须有更好的方法来确保每个 data.frame 具有相同数量的行,但对于我的应用程序,我可以保证它们只有几行不同,所以我只是修剪掉多余的行。

chan.dt <- as.data.table(matrix(unlist(chan.dt),
                 ncol = length(unique(sample.table$Channel)), 
                 byrow=TRUE))

这将使您返回一个大数据表,其中以 Channels 作为列。

chan.dt[,Class:=
         as.factor(rep(0:1,each=sampling.factor/2*nrow(original.table)/ncol(chan.dt))[1:cut.fringes])]

最后,我重新绑定了我的分类变量。这些表应该已经按类别排序,所以这将匹配。这假设您拥有包含所有数据的原始表;还有其他方法可以做到这一点。

ggpairs(data=chan.dt,
        columns=1:length(unique(sample.table$Channel)), colour="Class",axisLabels="show")

现在它可以用上面的方法绘制了。

【讨论】:

  • 按照我在上面的设置方式,您仍在丢弃行,但现在您可以选择在那里做什么。那些比我更熟练的人可能知道一些使用不规则桌子的技巧可以让它发挥作用。
【解决方案3】:

据我所知,ggpairs() 无法解决这个问题。此外,您不填写“假”数据是绝对正确的。如果在这里建议合适,我会建议使用不同的绘图方法。例如

 cor.data<- cor(data,use="pairwise.complete.obs") #data correlations ignoring pair-wise NA's
 chart.Correlation(cor.data) #library(PerformanceAnalytics)

或使用此处的代码http://hlplab.wordpress.com/2012/03/20/correlation-plot-matrices-using-the-ellipse-library/

【讨论】:

    【解决方案4】:

    我看到这是一个旧帖子。最近我遇到了同样的问题,但在网上还是找不到解决办法。所以我在下面提供了我的解决方法。

    我认为目的是使用成对的完整观察值进行绘图(即以特定于ggpairs 网格图的每个面板/方面的方式),而不是对所有变量使用完整的观察值。前者将最大程度地保留“可用”的观察结果,而不会通过估算缺失值来引入“人工”数据。到目前为止,ggpairs 似乎仍然不支持这一点。我的解决方法是:

    1. 用数据中不存在的另一个值编码NA,例如对于数值变量,我将 NA 替换为 -666 用于我的数据集。对于每个数据集,您始终可以选择超出其数据值范围的内容。顺便说一句,Inf 似乎不起作用;
    2. 然后使用用户创建的绘图函数检索成对的完整案例。例如,对于下三角形中连续变量的散点图,我会这样做:
    scat.my <- function(data, mapping, ...) {
      x <- as.character(unclass(mapping$x))[2] # my way of parsing the x variable name from `mapping`; there may be a better way
      y <- as.character(unclass(mapping$y))[2] # my way of parsing the y variable name from `mapping`; there may be a better way
      dat <- data.table(x=data[[x]], y=data[[y]])[x!=-666 & y!=-666] # I use the `data.table` package; assuming NA values have been replaced with -666
      ggplot(dat, aes(x=x, y=y)) +
        geom_point()
    }
    
    ggpairs(my.data, lower=list(continuous=scat.my), ...)
    

    上三角形和对角线也可以类似地进行。这有点费力,因为所有的绘图功能都需要通过上面的自定义修改手动重新完成。但它确实奏效了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-16
      • 2020-08-19
      • 1970-01-01
      • 2016-03-23
      • 2021-12-09
      • 1970-01-01
      相关资源
      最近更新 更多