在R中使用数据框的列绘制多个箱线图

4

我有一个数据框,其中包含一列分类数据(两个可能的值)和多个变量列。我需要绘制多个箱线图,每个图都是为一个变量列绘制的。每张图将比较第一列中给定的两个分类组之间的变量值。到目前为止,我已经通过为每个列编写单独的绘图调用来使其工作。

#CREATE DATASET
mydata <- data.frame(matrix(rlnorm(30*10,meanlog=0,sdlog=1), nrow=30))
colnames(mydata) <- c("categ", "var1","var2", "var3","var4", "var5", "var6", "var7", "var8", "var9")
mydata$var2 <- mydata$var2*5
mydata$categ <- sample(1:2)
mydata

#LAYOUT
par(mfrow=c(3,3), mar=c(4,4,0.5,0.5), mgp = c(1.5, 0.3, 0), tck = -0.01)

#BOXPLOTS
boxplot(var1 ~ categ, data = mydata, outpch = NA, ylim = c(0, 8), Main = "Title", ylab="VarLevel", tck = 1.0, names=c("categ1","categ2"))
stripchart(var1 ~ categ, data = mydata, vertical = TRUE, method = "jitter", ylim = c(0, 8), pch = 21, cex = 1, col=c(rgb(255, 0, 0, 100, max = 255), rgb(0, 0, 255, 100, max = 255)), bg = rgb(255, 255, 255, 10, max = 255), add = TRUE)
test <- wilcox.test(var1 ~ categ, data = mydata)
pvalue <- test$p.value
pvalueformatted <- format(pvalue, digits=3, nsmall=2)
mtext(paste(colnames(mydata)[2], " p = ", pvalueformatted), side=1, line=-13, at=0.9, cex = 0.6)

boxplot(var2 ~ categ, data = mydata, outpch = NA, ylim = c(0, 40), Main = "Title2", ylab="VarLevel", tck = 1.0, names=c("categ1","categ2"))
stripchart(var2 ~ categ, data = mydata, vertical = TRUE, method = "jitter", ylim = c(0, 40), pch = 25, cex = 1, col=c(rgb(255, 0, 0, 100, max = 255), rgb(0, 0, 255, 100, max = 255)), bg = rgb(255, 255, 255, 10, max = 255), add = TRUE)
test <- wilcox.test(var2 ~ categ, data = mydata)
pvalue <- test$p.value
pvalueformatted <- format(pvalue, digits=3, nsmall=2)
mtext(paste(colnames(mydata)[3], " p = ", pvalueformatted), side=1, line=-13, at=0.9, cex = 0.6)

两个问题:
1)我想使用一个函数或for循环为每个数据列编写绘图调用的脚本。不确定如何做到这一点。我看到了一些相关的帖子,但无法完全理解。目前正在尝试使用基本函数,但如果必要的话可以考虑ggplot或其他函数库。
2)作为循环/函数的一部分,有没有办法调整每个绘图的y轴刻度以适应变量的范围?因此,对于给定的列,如果最大值为2,则y轴刻度将上升到4。如果最大值为100,则y轴将上升到110。
感谢您的建议。

一个好的、可重现的问题——谢谢。 - jbaums
1个回答

4
我会在一个列数字的向量上应用sapply函数,并在函数内部将mydata子集化为感兴趣的列。通过迭代列数字而不是列本身,您可以轻松访问正确的colname,以便稍后添加到图中。
您还需要在第3个边(顶部)上添加一个小的外边距(oma),以便可以在前3个图中打印p值。
针对您的第二个问题——如何缩小y轴限制以适应数据范围——如果您指定outline=FALSE以抑制离群值的绘制,则这将自动完成。(在您的代码中,您只需提供NA作为绘图字符来隐藏它们,但boxplots在确定轴限制时仍将其视为数据的一部分。) 但是,通过设置outline=FALSE,计算出的y限制将不包含任何否则将由调用stripchart(我现在已经修改为points,因为它更简单)绘制的离群值。
par(mfrow=c(3,3), mar=c(3, 3, 0.5, 0.5), mgp = c(1.5, 0.3, 0), tck = -0.01,
    oma=c(0, 0, 1, 0))

sapply(seq_along(mydata)[-1], function(i) {
  y <- mydata[, i]
  boxplot(y ~ mydata$categ, outline=FALSE, ylab="VarLevel", tck = 1.0, 
          names=c("categ1","categ2"), las=1)
  points(y ~ jitter(mydata$categ, 0.5), 
     col=ifelse(mydata$categ==1, 'firebrick', 'slateblue'))
  test <- wilcox.test(y ~ mydata$categ)
  pvalue <- test$p.value
  pvalueformatted <- format(pvalue, digits=3, nsmall=2)
  mtext(paste(colnames(mydata)[i], " p = ", pvalueformatted), side=3, 
        line=0.5, at=0.9, cex = 0.6)  
})

注意,我还修改了您的

你比我早到了大约2秒钟。 :) - Rich Scriven
1
这几天我们一直在进行一场史诗级的战斗 ;) - jbaums
非常棒的解决方案,正是我正在寻找的。谢谢。我想确保我理解:seq_along在做什么?此外,如果有大量列,如何限制每页为12个图?我需要将数据框拆分成单独的12列数据框吗? - marcel
你可以使用seq_along函数来测试它的功能。seq_along(mydata) 返回一个整数序列从1到length(mydata),在大多数情况下它相当于1:ncol(mydata)或者1:length(mydata)(但是如果mydata是一个矩阵而不是数据框,length就会出问题)。我们去掉了这个序列的第一个元素,因为我们不把类别作为要绘制的数据处理。 - jbaums
我们使用 mfrow=c(3, 3) 来确保只绘制了9个图。之后会生成一个新的绘图窗口。如果您想要4行3列,可以使用 mfrow=c(4, 3)。如果您使用的是RStudio,则可以在各个绘图窗口之间左右滚动并按需导出它们。或者,在整个sapply块之前插入png('some_boxplots%d.png'),并在其后插入dev.off(),文件名中的%d将打开分页,以4x3个图命名为 'some_boxplots1.png','some_boxplots2.png'等。 - jbaums
刚刚上了一堂很棒的R语言课程。非常感谢! - marcel

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