在R中的映射函数中向列表对象添加元素

11

我正在使用GGally::ggpairs创建散点图矩阵。我正在使用自定义函数(下面称为my_fn)来创建左下角的非对角子图。在调用该自定义函数的过程中,会计算每个子图的信息,并且我希望将其保存以备后用。

在下面的示例中,每个h@cID都是一个具有100个值的int[]结构。在my_fn中共创建10次(每个左下角的非对角子图一次)。我正在尝试将这10个h@cID结构全部存储到listCID列表对象中。

我尝试了这种方法,但没有成功,我还尝试了其他几种变体(例如将listCID作为my_fn的输入参数,或在最后返回它),但也没有成功。

是否有可能通过my_fn高效地存储这十个h@cID结构以备后用?我感觉有几个语法问题我不太熟悉,这可能解释了我卡住的原因,如果术语不当,请告诉我,我很乐意更改这个问题的标题。谢谢!

library(hexbin)
library(GGally)
library(ggplot2)

set.seed(1)

bindata <- data.frame(
    ID = paste0("ID", 1:100), 
    A = rnorm(100), B = rnorm(100), C = rnorm(100), 
    D = rnorm(100), E = rnorm(100))
    bindata$ID <- as.character(bindata$ID
)

maxVal <- max(abs(bindata[ ,2:6]))
maxRange <- c(-1 * maxVal, maxVal)

listCID <- c()

my_fn <- function(data, mapping, ...){
  x <- data[ ,c(as.character(mapping$x))]
  y <- data[ ,c(as.character(mapping$y))]
  h <- hexbin(x=x, y=y, xbins=5, shape=1, IDs=TRUE, 
              xbnds=maxRange, ybnds=maxRange)
  hexdf <- data.frame(hcell2xy(h),  hexID=h@cell, counts=h@count)
  listCID <- c(listCID, h@cID)
  print(listCID)
  p <- ggplot(hexdf, aes(x=x, y=y, fill=counts, hexID=hexID)) + 
            geom_hex(stat="identity")
  p
}

p <- ggpairs(bindata[ ,2:6], lower=list(continuous=my_fn))
p

输入图像描述


2
你可以将额外的信息添加为属性。所以在 hexdf <- data.frame(...) 这一行之后,使用 attr(hexdf, "cID") <- h@cID(并删除两行代码中的 listCID)。然后,您可以通过查看单个图表来访问,例如 str(p[2,1]),并使用 attr(p[2,1]$data, "cID") 提取。 - user20650
2个回答

5
如果我正确理解了您的问题,那么可以使用`<<-`运算符相对容易但不太优雅地解决。使用它,您可以从函数的内部作用域中分配类似全局变量的内容。在执行函数之前,将`listCID <- NULL`设置为空,然后在函数内部使用`listCID << - c(listCID, h@cID)`。
listCID = NULL

my_fn <- function(data, mapping, ...){
  x = data[,c(as.character(mapping$x))]
  y = data[,c(as.character(mapping$y))]
  h <- hexbin(x=x, y=y, xbins=5, shape=1, IDs=TRUE, xbnds=maxRange, ybnds=maxRange)
  hexdf <- data.frame (hcell2xy (h),  hexID = h@cell, counts = h@count)

  if(exists("listCID")) listCID <<-c(listCID,h@cID)

  print(listCID)
  p <- ggplot(hexdf, aes(x=x, y=y, fill = counts, hexID=hexID)) + geom_hex(stat="identity")
  p
    }

了解更多关于作用域的内容,请参考 Hadley 的优秀著作《Advanced R》:http://adv-r.had.co.nz/Environments.html


0
通常情况下,试图在一个函数中返回两个不同的结果并不是一个好的做法。在您的情况下,您想要返回绘图和计算结果(hexbin cIDs)。
更好的方法是分步计算您的结果。每一步都应该是一个单独的函数。第一个函数的结果(计算hexbins)可以作为多个后续函数的输入(查找cIDs和创建绘图)。接下来是您可以重构代码的众多方式之一:
  • calc_hexbins() 是生成所有六边形箱的函数。该函数可以返回一个命名列表的六边形箱(例如,list(AB = h1, AC = h2, BC = 43))。这是通过枚举列表(A、B、C、D 和 E)的所有可能组合来实现的。缺点是你正在复制一些已经在 ggpairs() 中存在的逻辑。
  • gen_cids() 将六边形箱作为输入,并生成所有 cID。这是一个简单的操作,你可以循环遍历列表中的所有元素并获取 cID。
  • create_plot() 也将六边形箱作为输入,这是你实际生成图表的函数。在这里,你可以添加一个额外的参数用于六边形箱的列表(你的 GGally 包中有一个函数 wrap() 可以做到这一点)。而不是计算六边形箱,你可以在先前生成的命名列表中通过将 A 和 B 组合成字符串来查找它们。

这样做可以避免使用属性或全局变量等笨拙的方法。当然,这些方法也能够工作,但在维护代码时常常会带来麻烦。不幸的是,这样做可能会让你的代码变得稍微冗长一些,但这也可能是一件好事。


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